使用 std::unique_ptr.reset() 更改指针下的对象
Posted
技术标签:
【中文标题】使用 std::unique_ptr.reset() 更改指针下的对象【英文标题】:Using std::unique_ptr.reset() to change the object under pointer 【发布时间】:2017-05-20 17:07:56 【问题描述】:我想使用代理设计模式来使我的对象的功能“无效”。在我的设计中,用作无效对象的 NullObject 是一个静态变量。
将 std::unique_ptr.reset 与指向静态变量的指针一起使用是解决此问题的合法方法吗?
我曾尝试在 Visual Studio 中执行此操作,并且一切正常,但是我担心 unique_ptr 析构函数以及它可能想尝试对静态变量做什么。
class Proxy : public IExtendedInterface
public:
Proxy(std::unique_ptr<IInterface> object)
: heldObject(std::move(object))
void invalidate() override
heldObject.reset(&nullObject);
void someMethod() override
heldObject->someMethod();
private:
std::unique_ptr<IInterface> heldObject;
static NullObject nullObject;
;
class Object : public IInterface
public:
void someMethod() override
std::cout << "Called from object";
;
class NullObject : public IInterface
public:
void someMethod() override
std::cout << "Called from NullObject";
;
;
【问题讨论】:
在静态分配的对象上创建一个 unique_ptr 点不是一个好主意(事实上,您将进入 UB 领域)。当你想处理动态分配的东西时,你可以使用智能指针。 我知道,但我需要 unique_ptr 用于通过构造函数移动的动态分配对象。 unique_ptr 没有问题,问题是你使用那个静态分配的对象来表示指针不再使用。 那么我是否应该将 holdObject 和静态 nullObject 都设为 shared_ptr ? 我根本不相信你需要一个 nullObject。 【参考方案1】:你不需要任何特殊的nullObject,你可以调用std::unique_ptr.reset()
,std::unique_ptr::operator bool
会返回false,表示指针持有空指针,不应该被取消引用。
还要注意,如果 unique_ptr
指向静态分配的对象,如果它在此状态下超出范围,可能会导致双重释放问题。
【讨论】:
对于通过指针引用的静态分配对象,即使是一个空闲也是错误的。【参考方案2】:这是一个有趣的问题。首先,我会质疑对“空”对象的需求。它们确实有它们的用途,但还有其他方法可以使用。
一种解决方案是为每个指针简单地创建一个新的“唯一”NullObject
,但如果您确定只有 一个 NullObject
,那么可以考虑一个 单例模式。
static 对象的一个问题是您无法始终控制它们的创建时间和销毁时间。单例模式解决了创建问题,但销毁问题取决于您的情况。
如果 NullObject
的析构函数永远不需要被调用,你可以简单地使用基于 pointer 的单例,它永远不会被破坏。
然后您可以为您的unique_ptr
创建一个自定义删除器,以避免删除单例。
类似这样的:
class Object
public:
virtual ~Object() = default;
;
// make this inline or extern (and define it elsewhere)
// to ensure only one instance
inline Object* null_object()
// create the null version here
class NullObject: public Object;
// Never gets deleted so it is SAFE during program close-down
// ASSUMING calling its destructor is not required!
static NullObject* null_object = new NullObject;
return null_object;
// special deleter avoids deleting the null object
struct ObjectDeleter
void operator()(Object* o) const
if(o != null_object())
delete o;
;
// special version of a unique_ptr that uses the deleter
using ObjectUniquePtr = std::unique_ptr<Object, ObjectDeleter>;
现在在您的应用程序代码中使用ObjectUniquePtr
。
auto op = ObjectUniquePtr(null_object());
【讨论】:
以上是关于使用 std::unique_ptr.reset() 更改指针下的对象的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?