#include <memory>
class bar{};
void foo(bar &object){
std::unique_ptr<bar> pointer = &object;
}
我想将指针的地址分配给指针。上面的代码显然不会编译,因为赋值运算符的右侧需要是std :: unique_ptr。我已经尝试过了:
pointer = std::make_unique<bar>(object)
但它在编译过程中会抛出许多错误。我怎么能这样做?
更新
如答案所述 - 使用std::unique_ptr::reset
方法导致未定义的行为。现在我知道,在这种情况下我应该使用标准指针。
答案 0 :(得分:13)
void foo(bar &object){
std::unique_ptr<bar> pointer;
pointer.reset(&object);
}
但请注意不建议,不应为传递给函数的引用创建unique_ptr
。在函数结束时,当pointer
被销毁时,它也将尝试销毁object
,并且在函数调用之外它将不可用,从而导致访问内存错误。 / p>
示例:这将编译,但会给出运行时错误。
struct bar{ int num;};
void foo(bar &object){
std::unique_ptr<bar> pointer;
pointer.reset(&object);
}
int main()
{
bar obj;
foo(obj);
obj.num; // obj is not a valid reference any more.
return 0;
}
另一方面,您可能需要考虑使用shared_ptr这可以帮助您做出决定:unique_ptr or shared_ptr?。
答案 1 :(得分:4)
您可以致电std::unique_ptr::reset
:
pointer.reset(&object);
但真正的问题是:这是否真的按照您的预期进行?如果对象不是通过new
创建的,则上述情况可能非常危险。鉴于您没有提供更多信息,可能有一个有效的用例 - 但如果没有这些信息,它似乎是未来麻烦的可能来源。您在示例中实际执行的操作是使用对象,即在调用函数后,unique_ptr
的生命周期结束且对象已被删除。如果调用者记录/清楚这一点,则可能没问题 - 否则重新考虑设计。即使这是预期的设计,最好使用unique_ptr
作为函数本身的参数:
void foo(std::unique_ptr<bar> pointer)
{
// ...
}
这有两件事:
答案 2 :(得分:4)
您只能分配另一个unique_ptr
或nullptr
。如果你考虑一下,这也是有道理的(虽然reset
会让你做你想做的事,但我认为这实际上是unique_ptr
}中的一个错误或缺陷。
unique_ptr
是指向对象的独占所有者。当它超出范围时,它将删除该对象
这意味着您的函数具有 sink 语义。您传入的指针(或者更确切地说是指向对象“)被消耗掉,也就是说,它在函数内部”消失“(下沉)。您通过引用传递一个对象(一个甚至不一定是堆分配的对象)如果你传入一个带有自动存储空间的物体,请准备一个惊喜!)然后它突然消失了.Bang。
应正确传达接收语义。您应该传递unique_ptr
作为函数参数。无法复制唯一指针,因此这将强制该函数的用户使用std::move
,创建意识的实际情况。
让一个物体“消失”是一个令人讨厌的惊喜,这不应该只是无意中发生。
答案 3 :(得分:3)
请允许我让你失望,但你不会。你有一个引用,它可以指向一个动态分配的对象或一个堆栈分配的对象,或者,也许是一个动态分配的数组中的一个对象,它没有单独分配。
您希望将其地址放在将自动在该地址上调用delete的类中。对于上述大多数情况,这是无效的。那是错的。因此,永远不应该传递引用并将引用的地址放在智能指针中。特别是没有重置()。
最多,您可能要做的是使用新分配的对象初始化智能指针,例如:
auto ptr = std::unique_ptr<X>(new X(p1, p2));
请勿使用参考地址。永远。没原因。这在道德上是错误的。这不是因为参考地址的使用无效,因为它可以有效使用;它是因为两个月后新同事会想用智能指针来使用该地址,因为他现在已经听到了这个地址,然后来到Stack Overflow并阅读他们应该对该指针使用“reset”。这是错的,痛苦的错误。
答案 4 :(得分:1)
您正在寻找的功能是reset()
。这是一个例子:
pointer.reset(&object);
此处pointer
是unique_ptr
。调用reset()
将销毁pointer
管理的上一个对象(如果有的话),并使object
成为pointer
的当前管理对象。
或者,如果您想在初始化object
时将管理对象设为unique_ptr
:
std::unique_ptr<bar> pointer(&object);
尽管如此警告:{/ strong> object
如果您要new
进行管理,则应与unique_ptr
分配,因为{ {1}}可能会尝试在其上调用unique_ptr
。如果它不是使用delete
创建的,请不要将其包裹在new
中,这不是他们的目的。
答案 5 :(得分:1)
我可以看到,你想拥有unique_ptr对象,它指向内存中的某个对象,但你不想转移内存的所有权。
您需要为对象创建自定义删除器,实际上不会删除对象:
class bar{};
struct barfakedeleter
{
void operator()(bar*){/* do nothing here*/}
};
unique_ptr是一个模板,其中第二个参数是对象的删除者。默认情况下它是default_deleter,但你可以用这个假的交换它:
void foo(bar& object)
{
unique_ptr<bar,barfakedeleter> pointer(&object);
....
}
帖子编辑: 与shared_ptr相同,但由于shared_ptr可以强制转换为对象继承树中的其他shared_ptr,因此删除操作不会存储在类模板参数中,而是作为实例成员过去。这实际上使IMO更容易使用:
void foo(bar& object)
{
shared_ptr<bar> pointer(&object,[](bar*){}); // just use anonymous function, which will not delete the object
}
您也可以自行发布资源:
shared_ptr<ObjectClass> pointer(GetObject(),[](ObjectClass* obj){ ReleaseTheObject(obj);});