[英]How to assign the address of an existing object to a smart pointer?
#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
方法导致未定义的行为。 现在我知道,在这种情况下我应该使用标准指针。
void foo(bar &object){
std::unique_ptr<bar> pointer;
pointer.reset(&object);
}
但请注意,这是不推荐的,您不应为传递给函数的引用创建unique_ptr
。 在函数结束时,当pointer
被销毁时,它也会尝试销毁object
,并且它在函数调用之外不可用,从而导致访问内存错误。
示例:这将编译,但会出现运行时错误。
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 还是 shared_ptr? .
您只能分配另一个unique_ptr
或nullptr
。 如果你考虑一下,这也是有道理的(虽然reset
会让你做你想做的,但我认为这实际上是unique_ptr
一个错误或缺陷)。
unique_ptr
是指向对象的唯一所有者。 当它超出范围时,它将删除该对象。
这意味着您的函数具有接收器语义。 您传入的指针(或者更确切地说是指向的对象)被消耗,也就是说,它在函数内部“消失”(下沉)。您通过引用传入一个对象(一个甚至不一定是堆分配的对象) ,如果您传入具有自动存储功能的对象,请准备好惊喜!)然后它突然消失了。砰。
应该正确传达接收器语义。 您应该将unique_ptr
作为函数参数传递。 唯一指针无法复制,因此这将强制该函数的用户使用std::move
,从而了解实际发生的情况。
一个对象“消失”是一个令人讨厌的惊喜,这不应该只是无意中发生的。
你可以调用std::unique_ptr::reset
:
pointer.reset(&object);
但真正的问题是:这真的按照你的期望去做吗? 如果对象不是通过new
创建的,则上述内容可能非常危险。 鉴于您没有提供更多信息,您可能有一个有效的用例 - 但如果没有这些信息,它似乎是未来麻烦的可能来源。 您在示例中有效地做的是使用该对象,即在调用该函数之后, unique_ptr
的生命周期结束并且该对象已被删除。 如果这对调用者记录/清楚,则可能没问题 - 否则重新考虑设计。 即使这是预期的设计,最好使用unique_ptr
作为函数本身的参数:
void foo(std::unique_ptr<bar> pointer)
{
// ...
}
这有两件事:
让我让你失望,但你没有。 你有一个引用,它可以指向一个动态分配的对象或一个堆栈分配的对象,或者,一个动态分配的数组中的对象,它不是单独分配的。
您想将其地址放在一个类中,该类将自动对该地址调用 delete。 对于上面介绍的大多数情况,这是无效的。 那是错的。 因此,永远不应传递引用并将引用的地址放入智能指针中。 尤其是不使用reset()。
最多,您可能想要做的是使用新分配的对象初始化智能指针,例如:
auto ptr = std::unique_ptr<X>(new X(p1, p2));
永远不要取参考的地址。 曾经。 没原因。 这在道德上是错误的。 不是因为引用地址的使用无效,而是可以有效使用; 这是因为两个月后,新同事将要使用带有智能指针的地址,因为他听说现在已经这样做了,然后来到 Stack Overflow 并读到他们应该对那个指针使用“重置”。 这是错误的,痛苦的错误。
您正在寻找的功能是reset()
。 下面是一个例子:
pointer.reset(&object);
这里的pointer
是一个unique_ptr
。 调用reset()
将销毁之前由pointer
管理的对象(如果有的话),并使object
成为pointer
的当前管理对象。
或者,如果您想在初始化unique_ptr
时使object
成为托管对象:
std::unique_ptr<bar> pointer(&object);
不过有一句警告:如果您要通过unique_ptr
管理object
则应使用new
分配它,因为unique_ptr
可能会尝试对其调用delete
。 如果它不是用new
创建的,请不要将它包装在unique_ptr
,那不是它们的用途。
我能看到的是,你想要一个 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);});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.