2017-02-08 63 views
0

我很好奇你会在什么情况下创建一个对象的浅拷贝,而不是简单地将对象的引用传递给对象,或者在C++中创建对象的深层副本?在C++中使用浅拷贝而不是参考的原因?

我的理解是,如果你有一个只读或不可变的对象,你只需要使用一个引用。如果您需要在不更改原始内容的情况下对副本进行更改,或者将某些数据编组到不同的内存地址空间,则可以进行深度复制。

我可以看到在写入副本中使用浅拷贝(在写入对象并完成深层副本之前),但是您是否还有其他原因希望使用浅拷贝?

编辑:试图澄清问题。

+0

在你的例子中,我说的是传递一个T&around,引用(或可能是一个指针)到根对象。 – vijay267

回答

2

这里上表中的两个选项(假定C++ 11)为:

  1. 具有浅拷贝构造/赋值操作符的对象。

  2. 一个对象,要么是昂贵的复制或根本不可复制。给定C++ 11,它会有一个浅层移动构造函数/赋值运算符。

C++最终是一种面向价值的语言。直到C++ 17,像这样简单:

T t = someFuncReturningT(); 

至少理论上会引起复制/移动操作。 C++ 17的保证elision确保不会发生这种情况,但在此之前,这被认为是执行复制/移动到T。当然,几乎每个编译器都会忽略它。但它在理论上仍然存在。

但是,对于移动操作,没有浅拷贝并不是件坏事。

为什么你会希望浅拷贝与昂贵的拷贝+浅层移动的主要原因是其中拷贝不仅仅是“浅拷贝”的类型。例如,shared_ptr。复制不只是复制一个或两个指针;你也会碰到参考计数。事实上,这是shared_ptr作为一种类型的设计的结果:允许多个所有者为一个对象。

而唯一的方法就是如果每个业主都有自己的副本。因此,在这方面,复制必须是“浅薄的”。

所以它的优势在于它是对象设计的一部分。


如果您在谈论pre-C++ 11天,浅拷贝更有意义。 Post-C++ 11,你可以依赖廉价的移动操作,但是C++ 11之前的版本不可用。所以浅拷贝几乎是通过值合理返回对象的唯一方法。

+2

这是如何解决OP的理解:“如果你有一个只读或不可变的对象,你只想使用一个引用”? –

+0

@barakmanos:引用什么?你不能使用裸const char *,因为它没有你想要的行为。 –

+1

嗯,我认为OP是指结构或类。术语* shallow-copy *对于除此之外的任何其他内容是否有效? –

-2

我首先想到的是移动一个对象。

假设你在新的操作符中在类中分配了一个内存。

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    void destroy() 
    { 
     delete [] data; 
    } 

    A (const A& copy) 
    { 
     data = copy.data; 
    } 


    int* data 
} 

比让我们说要复制这个对象。为什么不直接将指针复制到数据而是复制所有数据。

A calculateA() 
{ 
    A returnVal; 
    for (int i = 0; i < 50; i++) 
     returnVal.data[i] = i; 
    return returnVal; 
} 

在这种情况下,浅拷贝是有利的。

A (const A& copy) 
{ 
    data = copy.data; 
} 

A newA = calculateA(); 
// do stuff with newA 
newA.destroy(); 

我相信也会有其他一些原因。

要避免复制副本时的双重删除可以设置为空。

#include <iostream> 
#include <utility> 

struct A 
{ 
    A() 
    { 
     data = new int[50]; 
    } 

    ~A() 
    { 
     if (data) 
     delete [] data; 
    } 

    A (A& copy) 
    { 
     data = copy.data; 
     copy.data = nullptr; 
    } 

    int* data; 
}; 


int main() 
{ 
    A aVal; 
    for (int i = 0; i < 50; i++) 
     aVal.data[i] = i; 

    A anotherVal = aVal; 

    int i = 10; 
    while (i--) 
     std::cout << anotherVal.data[i]; 
} 
+0

请解释投票,以便我从错误中学习。 –

+0

“*在这种情况下,浅拷贝可以是有利的。”*你刚刚解释了浅拷贝可以很容易被破坏*。因为在你的情况下,你将尝试删除'data'数组*两次*。 –

+0

这就是为什么我说“可以”,因为这个问题也问“可能是什么原因”。通过简单的指针检查就可以轻松避免。 –

0

想象一下下面的例子:

shared_ptr<T> p1(new T); 
... 
shared_ptr<T> p2 = p1; 

这里P2是P1的浅表副本。你可以在这里使用引用,但你不能如果你返回它:

shared_ptr<T> f() { 
    shared_ptr<T> p1(new T); 
    return p1; 
} 
+0

这将自动从。当然,在C++ 11中。 –

+0

在第二个例子中,但不是第一个例子。 –

+0

没错,但是OP的观点仍然(可能)是有效的:你不必严格需要浅拷贝才能以合理的方式对对象进行操作。 –