在C++中使用浅拷贝而不是引用的原因
Reasons to use a shallow copy instead of a reference in C++?
我很好奇,在什么情况下,你会真正创建一个对象的浅拷贝,而不是简单地在C++中传递对该对象的引用或对所述对象进行深度拷贝?
我的理解是,如果你有一个只读或不可变的对象,你只需要使用一个引用。如果您需要在不更改原始数据的情况下对副本进行更改,或者将一些数据封送到不同的内存地址空间,则需要进行深度复制。
我可以看到在写时复制的情况下(在你写对象并完成深度复制之前)使用浅层复制,但你想使用浅层副本还有其他原因吗?
编辑:试图澄清问题。
这里表上的两个选项(假设C++11)是:
-
一个具有浅复制构造函数/赋值运算符的对象。
-
具有的对象要么复制成本高,要么根本不可复制。给定C++11,它将有一个浅移动构造函数/赋值运算符。
C++最终是一种面向价值的语言。直到C++17,像这样简单的东西:
T t = someFuncReturningT();
至少在理论上会引发复制/移动操作。C++17的保证省略确保了这种情况不会发生,但在那之前,这被认为是执行到T
中的复制/移动。当然,几乎每个编译器都会忽略它。但理论上它仍然存在。
然而,对于移动操作,没有浅拷贝并不是一件坏事。
您想要浅层复制与昂贵的复制+浅层移动的主要原因是复制不仅仅是"浅层复制"的类型。例如CCD_ 2。复制不仅仅是复制一两个指针;您还可以增加引用计数。事实上,这是shared_ptr
作为一种类型设计的结果:允许一个对象有多个所有者。
唯一的方法是每个所有者都有自己的副本。因此,在这方面,复制必须是"肤浅的"。
因此,优势在于它是对象设计的一部分。
如果你谈论的是C++之前的11天,浅拷贝更有意义。在C++11之后,你可以依靠廉价的移动操作,但在C++11之前,这是不可用的。因此,浅拷贝几乎是合理地按值返回对象的唯一方法。
想象一下下面的例子:
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;
}
我首先想到的是移动一个对象。
假设你在课堂上用新操作符分配了一个内存。
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];
}
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 如何引用基类的派生类?