我很好奇你在什么情况下实际创建一个对象的浅表副本而不是简单地传递一个对象的引用或者用C ++制作一个所谓对象的深层副本?
我的理解是,如果你有一个只读或不可变的对象,你只想使用一个引用。如果您需要在不更改原件的情况下对副本进行更改,或者将某些数据封送到不同的内存地址空间,则需要进行深层复制。
我可以看到在写入案例的副本中使用浅拷贝(在写入对象并完成深拷贝之前),但是还有其他一些原因你想要使用浅拷贝吗? / p>
编辑:试图澄清问题。
答案 0 :(得分:2)
这里的两个选项(假设C ++ 11)是:
具有浅复制构造函数/赋值运算符的对象。
复制成本高或根本无法复制的对象。给定C ++ 11,它将有一个浅的移动构造函数/赋值运算符。
C ++最终是一种以价值为导向的语言。在C ++ 17之前,就像这样简单:
T t = someFuncReturningT();
至少理论上会激发复制/移动操作。 C ++ 17保证省略确保不会发生这种情况,但在此之前,这被视为执行复制/移动到T
。当然,几乎每个编译器都会忽略它。但它理论上仍然存在。
然而,对于移动操作,没有浅拷贝并不是一件坏事。
您希望浅拷贝与昂贵的拷贝+浅移动的主要原因是复制不仅仅是“浅拷贝”的类型。例如shared_ptr
。复制不只是复制指针或两个;你也会引用一个引用计数。实际上,这是将shared_ptr
设计为类型的结果:允许多个所有者作为对象。
唯一的方法是,如果每个拥有者都拥有自己的副本。因此,在这方面,复制必须“浅薄”。
因此,优势在于它是对象设计的一部分。
如果您正在谈论前C ++ 11天,那么浅层复制更有意义。在Post-C ++ 11之后,你可以依靠廉价的移动操作,但是前C ++ 11,这是不可用的。因此,浅拷贝几乎是按值合理返回对象的唯一方法。
答案 1 :(得分: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;
}
答案 2 :(得分:-2)
我想到的第一件事就是移动一个物体。
假设您在课堂上使用new运算符分配了一个内存。
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();
我相信还有其他数千种原因。
为避免在复制时双重删除,可将其设置为null。
#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];
}