如何将现有对象的地址分配给智能指针?
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
方法导致未定义的行为。现在我知道,在这种情况下我应该使用标准指针。
您要找的函数是reset()
。这是一个例子:
pointer.reset(&object);
这里pointer
是一个unique_ptr
。调用 reset()
将销毁之前由 pointer
管理的对象(如果有的话),并使 object
成为 pointer
.
的当前管理对象
或者,如果您想在初始化 unique_ptr
时使 object
成为托管对象:
std::unique_ptr<bar> pointer(&object);
提醒一句: object
应该分配给 new
如果你打算用 unique_ptr
来管理它,因为 unique_ptr
可能会尝试在其上调用 delete
。如果它不是用 new
创建的,请不要将其包装在 unique_ptr
中,这不是它们的用途。
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 this can help you to decide: unique_ptr or shared_ptr?。
您可以致电 std::unique_ptr::reset
:
pointer.reset(&object);
但真正的问题是:这真的如您所愿吗?如果对象不是通过 new
创建的,上面的内容可能相当危险的。鉴于您没有提供更多信息,您 可能 有一个有效的用例 - 但如果没有这些信息,它似乎可能成为未来麻烦的根源。你在你的例子中有效地做的是你 consume 对象,即在函数被调用后 unique_ptr
的生命周期结束并且对象已被删除。如果这对调用者来说是 documented/clear,那可能没问题——否则请重新考虑设计。即使这是有意设计的,最好使用 unique_ptr
作为函数本身的参数:
void foo(std::unique_ptr<bar> pointer)
{
// ...
}
这有两件事:
- 它向调用者传达函数将取得所传递对象的所有权。
- 防止资源泄漏。
您只能分配另一个 unique_ptr
或 nullptr
。如果你仔细想想,这也是有道理的(虽然 reset
会让你做你想做的事,但我认为这实际上是 unique_ptr
中的一个错误或不足)。
A unique_ptr
是指向对象的独占所有者。当它超出范围时,它将删除该对象。
这意味着您的函数具有 sink 语义。您传入的指针(或者更确切地说是指向的对象“)被消耗,也就是说,它 "disappears" (下沉)在函数内部。您通过引用传入一个对象(一个对象甚至不一定是堆-allocated,如果你传入一个带有自动存储的对象,请做好准备!)然后突然就没了。Bang.
应正确传达接收器语义。您应该传递一个 unique_ptr
作为函数参数。无法复制唯一指针,因此这将迫使该函数的用户使用 std::move
,创建对实际发生的事情的意识。
拥有一个对象 "disappear" 是一个令人讨厌的惊喜,这不应该只是无意中发生的。
我看到的是,你想要 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);
....
}
post 编辑:
同样你可以用 shared_ptr 做,但是因为 shared_ptr 可以在对象的继承树中转换为其他 shared_ptr,删除器不存储在 class 模板参数中,但是它作为实例成员过去了。这实际上使使用 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);});
请允许我让你失望,但你没有。你有一个引用,它可以指向一个动态分配的对象或一个堆栈分配的对象,或者,也许,一个动态分配的数组中的对象,它不是单独分配的。
您想将其地址放在一个 class 中,它将自动对该地址调用 delete。这对上面介绍的大多数情况都是无效的。那是错的。因此,传递引用并将引用的地址放在智能指针中永远不应该这样做。特别是没有 reset().
至多,你可能想要做的就是用新分配的对象初始化智能指针,例如:
auto ptr = std::unique_ptr<X>(new X(p1, p2));
永远不要使用参考地址。曾经。没原因。这在道德上是错误的。不是因为引用地址的使用无效,因为它可以有效使用;这是因为两个月后,新同事将希望将该地址与智能指针一起使用,因为他听说现在就是这样做的,然后来到 Stack Overflow 并阅读他们应该为该指针使用“重置”。哪个错了,错的很惨。
#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
方法导致未定义的行为。现在我知道,在这种情况下我应该使用标准指针。
您要找的函数是reset()
。这是一个例子:
pointer.reset(&object);
这里pointer
是一个unique_ptr
。调用 reset()
将销毁之前由 pointer
管理的对象(如果有的话),并使 object
成为 pointer
.
或者,如果您想在初始化 unique_ptr
时使 object
成为托管对象:
std::unique_ptr<bar> pointer(&object);
提醒一句: object
应该分配给 new
如果你打算用 unique_ptr
来管理它,因为 unique_ptr
可能会尝试在其上调用 delete
。如果它不是用 new
创建的,请不要将其包装在 unique_ptr
中,这不是它们的用途。
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 this can help you to decide: unique_ptr or shared_ptr?。
您可以致电 std::unique_ptr::reset
:
pointer.reset(&object);
但真正的问题是:这真的如您所愿吗?如果对象不是通过 new
创建的,上面的内容可能相当危险的。鉴于您没有提供更多信息,您 可能 有一个有效的用例 - 但如果没有这些信息,它似乎可能成为未来麻烦的根源。你在你的例子中有效地做的是你 consume 对象,即在函数被调用后 unique_ptr
的生命周期结束并且对象已被删除。如果这对调用者来说是 documented/clear,那可能没问题——否则请重新考虑设计。即使这是有意设计的,最好使用 unique_ptr
作为函数本身的参数:
void foo(std::unique_ptr<bar> pointer)
{
// ...
}
这有两件事:
- 它向调用者传达函数将取得所传递对象的所有权。
- 防止资源泄漏。
您只能分配另一个 unique_ptr
或 nullptr
。如果你仔细想想,这也是有道理的(虽然 reset
会让你做你想做的事,但我认为这实际上是 unique_ptr
中的一个错误或不足)。
A unique_ptr
是指向对象的独占所有者。当它超出范围时,它将删除该对象。
这意味着您的函数具有 sink 语义。您传入的指针(或者更确切地说是指向的对象“)被消耗,也就是说,它 "disappears" (下沉)在函数内部。您通过引用传入一个对象(一个对象甚至不一定是堆-allocated,如果你传入一个带有自动存储的对象,请做好准备!)然后突然就没了。Bang.
应正确传达接收器语义。您应该传递一个 unique_ptr
作为函数参数。无法复制唯一指针,因此这将迫使该函数的用户使用 std::move
,创建对实际发生的事情的意识。
拥有一个对象 "disappear" 是一个令人讨厌的惊喜,这不应该只是无意中发生的。
我看到的是,你想要 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);
....
}
post 编辑: 同样你可以用 shared_ptr 做,但是因为 shared_ptr 可以在对象的继承树中转换为其他 shared_ptr,删除器不存储在 class 模板参数中,但是它作为实例成员过去了。这实际上使使用 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);});
请允许我让你失望,但你没有。你有一个引用,它可以指向一个动态分配的对象或一个堆栈分配的对象,或者,也许,一个动态分配的数组中的对象,它不是单独分配的。
您想将其地址放在一个 class 中,它将自动对该地址调用 delete。这对上面介绍的大多数情况都是无效的。那是错的。因此,传递引用并将引用的地址放在智能指针中永远不应该这样做。特别是没有 reset().
至多,你可能想要做的就是用新分配的对象初始化智能指针,例如:
auto ptr = std::unique_ptr<X>(new X(p1, p2));
永远不要使用参考地址。曾经。没原因。这在道德上是错误的。不是因为引用地址的使用无效,因为它可以有效使用;这是因为两个月后,新同事将希望将该地址与智能指针一起使用,因为他听说现在就是这样做的,然后来到 Stack Overflow 并阅读他们应该为该指针使用“重置”。哪个错了,错的很惨。