使用 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)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”