我打算让一个构造函数接受引用,然后创建指向作为引用传递的对象的指针,并将这些指针存储在一个字段中。但是,由于某种原因,我这样做,副本正在创建,我不明白为什么:
delete[]
我在这里缺少什么?复制发生在哪里?为什么?
答案 0 :(得分:2)
原因是std::make_shared<T>(t)
。 make_shared
将调用T
的构造函数,该构造函数接受它所给出的参数。你可以通过引用给它一个T
左值。
当然,调用复制构造函数。这是一件好事。如果你创建了一个共享指针到你传递的对象,你的代码可能会是一堆未定义的行为。
我建议您通过智能指针接受参数。它使您的类的用户可以从API本身清楚地了解所有权语义。
答案 1 :(得分:2)
我在这里缺少什么?复制发生在哪里?为什么?
从字面上回答问题,来自cppreference.com:
template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );
构造一个T
类型的对象,并使用std::shared_ptr
将其args
包装为T
的构造函数的参数列表。
在您的情况下,std::make_shared<T>(t)
(t
为T&
)会调用T::T(T const&)
并构建t
的副本。一个不正确的解决方案是在没有std::shared_ptr
的帮助下自己创建std::make_shared
...但在这种情况下,您将创建指向可能静态分配的对象的智能指针。这是坏,就像 Undefined Behavior 那样糟糕。
更好的解决方案是简单地避免创建通过引用传递的对象的智能指针,因为它可能会给调用者带来惊喜。更好地采取智能指针:
C(std::shared_ptr<T> t, std::shared_ptr<Types> ...args) { /* ... */ }
答案 2 :(得分:2)
std::make_shared<T>
分配一大块内存,足以存储类型为T的对象(如果有的话,用传递的参数初始化它),并附加一个控制块来管理共享所有权(如保持对象引用计数等。)。
+---------------+
| Control block |
| |
+ ............. +
| Object (T) |
| |
+---------------+
因此,即使您将引用传递给对象,make_shared
也会创建自己的“深层”副本(在其中构建其对象副本)如上所述分配的存储块的一部分。)