【问题标题】:Does C++ have a smart pointer like unique_ptr with a "destruct before constructing" semantics?C++ 是否有一个像 unique_ptr 这样的智能指针,它具有“构造前破坏”语义?
【发布时间】:2014-06-17 22:47:59
【问题描述】:

问题

考虑这个简单的类:

struct C {
   C(const char* name) : name(name) {
         cout << "constructing " << name  << endl;
   }
   
   ~C() {
       cout << "destructing " << name << endl;
   }
   
   string name;
};

我想要一个指向这个类的实例的指针,它通常会被另一个实例替换。但是,我希望在创建新实例之前 销毁当前实例。

错误的例子

如果我以正常方式使用unique_ptr,这将不起作用:

unique_ptr<C> c( new C("the first one"));
c.reset(new C("the second one"));

(不需要的)输出:

构建第一个

构建第二个

破坏第一个

摧毁第二个

丑陋的例子

可以达到预期的效果如下:

unique_ptr<C> c( new C("the first one"));
c.reset();  // explicitly destruct the first one first
c.reset(new C("the second one"));

输出:

构建第一个

破坏第一个

构建第二个

摧毁第二个

尝试的解决方案

这是我尝试创建具有这种行为的智能指针。 这样的智能指针是否已经存在?

template<typename Resource>
class ResourceManager {
  public:
    ResourceManager() {}

    template<typename... Arguments>
    ResourceManager(Arguments&&... args) {
      replace<Arguments...>(std::forward<Arguments>(args)...);
    }

    template<typename... Arguments>    
    void replace(Arguments&&... args) {
      resource.reset();
      resource.reset(new Resource(std::forward<Arguments>(args)...));
    }

  private:
    unique_ptr<Resource> resource;
};

template<typename Resource, typename... Arguments>
ResourceManager<Resource> make_resource_manager(Arguments... args) {
        return ResourceManager<Resource>(args...);
}

int main() {
   //ResourceManager<C, const char*> r("first1");
   auto r = make_resource_manager<C>("first1");
   r.replace("second1");
}

输出:

构建第一个

破坏第一个

构建第二个

摧毁第二个

编辑:将“参数...”模板移至函数级别。

编辑 2:现在正确转发“参数”。

【问题讨论】:

  • 为什么不分配一个新的呢? ptr = make_unique();
  • @paulm:因为他不希望两个同时存在。
  • 问题是为什么你不能有两个实例,你也不能重用现有的......这在某种程度上是一种脆弱的方法,你最终会得到 根本没有资源。
  • @DavidRodríguez-dribeas 我正在各种类似 istream 的对象 (ZipEntries) 之间切换,这些对象源自单个 ZipFile 对象(表示具有多个条目的 zip 存档)。在打开一个新的之前,我必须确保之前的 ZipEntry 被销毁。
  • 在我看来这是一个忽略实际问题的线程问题。

标签: c++ smart-pointers unique-ptr resourcemanager resource-management


【解决方案1】:

在 C++ 中尽可能避免在构造新状态之前破坏旧状态,因为这样无法提供强异常保证:“操作成功,或者抛出异常不做任何更改强>”。因此,标准库没有这样的(我什至无法命名添加它的框架)。

不过,天真和错误的复制构造函数有时会这样做。
如果您故意想要获得这种行为,没有什么比自己编写代码更好的了。
但是,请务必确定这是您想要的,并将其记录下来以供后代使用。

您的ResourceManager 似乎主要做您想做的事。
尽管如此,请务必确保方法名称/类名称显式调用您的非标准行为(ResourceManagerreplace 都不够具体)。

【讨论】:

    【解决方案2】:

    标准中没有类似的东西。我不知道你为什么想要这个特定的顺序,要么对象仍然存在并且你可以重用它,否则你最终可能会导致新对象无法构造和一个空的智能指针。

    【讨论】:

      【解决方案3】:

      您可以使用 C++ 中一直不受欢迎的预处理器:

      #define REPLACE_C(ptr,new_value) \
          do { \
              ptr.reset(); \
              ptr.reset(new_value); \
          while(false)
      
      unique_ptr<C> c( new C("the first one"));
      REPLACE_C(c, new C("the second one"));
      

      【讨论】:

      • 宏解决方案令人惊讶地更具可读性并且更不容易出错:)
      猜你喜欢
      • 2020-03-16
      • 2015-02-03
      • 2011-11-20
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      相关资源
      最近更新 更多