1

问题

考虑这个简单的类:

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

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

错误的例子

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

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:现在正确转发“参数”。

4

3 回答 3

5

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

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

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

于 2014-05-01T12:57:53.517 回答
2

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

于 2014-05-01T12:54:51.667 回答
2

您可以使用 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"));
于 2014-05-01T13:46:04.030 回答