Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;有一个智能指针,如带有“a”的唯一“ptr”;“先破坏后施工”;语义学? 问题_C++_Smart Pointers_Unique Ptr_Resourcemanager_Resource Management - Fatal编程技术网

C++ C++;有一个智能指针,如带有“a”的唯一“ptr”;“先破坏后施工”;语义学? 问题

C++ C++;有一个智能指针,如带有“a”的唯一“ptr”;“先破坏后施工”;语义学? 问题,c++,smart-pointers,unique-ptr,resourcemanager,resource-management,C++,Smart Pointers,Unique Ptr,Resourcemanager,Resource Management,考虑这个简单的类: struct C { C(const char* name) : name(name) { cout << "constructing " << name << endl; } ~C() { cout << "destructing " << name << endl; } string

考虑这个简单的类:

struct C {
   C(const char* name) : name(name) {
         cout << "constructing " << name  << endl;
   }
   
   ~C() {
       cout << "destructing " << name << endl;
   }
   
   string name;
};
(不期望的)输出:

构建第一个

构建第二个

破坏第一个

破坏第二个

丑恶的例子 可通过以下方式达到预期效果:

unique_ptr<C> c( new C("the first one"));
c.reset();  // explicitly destruct the first one first
c.reset(new C("the second one"));
unique_ptr c(新的c(“第一个”);
c、 重置();//先显式销毁第一个
c、 重置(新的c(“第二个”);
输出:

构建第一个

破坏第一个

构建第二个

破坏第二个

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

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");
}
模板
班级资源经理{
公众:
ResourceManager(){}
样板
ResourceManager(参数和参数){
替换(标准:正向(参数)…);
}
样板
无效替换(参数和参数){
reset();
重置(新资源(标准::转发(args)…);
}
私人:
独特的ptr资源;
};
样板
ResourceManager生成资源管理器(参数…参数){
返回ResourceManager(args…);
}
int main(){
//资源经理r(“first1”);
自动r=生成资源管理器(“第一个1”);
r、 替换(“第二次1”);
}
输出:

构建第一个

破坏第一个

构建第二个

破坏第二个

编辑:将“参数…”模板移动到函数级别


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

标准中没有类似的内容。我不知道你为什么想要那个特定的顺序,要么对象仍然是活动的,你可以重新使用它,要么你最终会得到无法构造的新对象和一个空的智能指针。

标准中没有这样的东西。我不确定为什么你想要那个特定的顺序,或者对象仍然活着,你可以重用它,或者你可以结束新的对象,而不能构造一个空的智能指针。C++:< /p> < p>在构建新的状态之前,尽可能地避免旧状态的发生,因为不能以这种方式提供强异常保证:“操作成功,或者在不更改任何内容的情况下抛出异常”。因此,标准库没有这样的功能(我甚至无法命名添加它的框架)

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

您的
ResourceManager
似乎主要是做您想做的事。

但是,要确保方法名称/类名明确地调用你的非标准行为(既不<代码>资源管理器< /C++ >也不<代码>替换< /代码>是足够具体的)。因为不能以这种方式提供强异常保证:“操作成功,或者在不更改任何内容的情况下抛出异常”。因此,标准库没有这样的功能(我甚至无法命名添加它的框架)

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

您的
ResourceManager
似乎主要是做您想做的事。

当然,要确保方法名/类名明确地调用你的非标准行为(既不是<代码>资源库>代码>也不是代码>替换< /C> >足够具体。

你可以使用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"));
#定义替换C(ptr,新值)\
做{\
ptr.reset()\
ptr.重置(新的_值)\
while(假)
独特的c(新的c(“第一个”));
更换_C(C,新的C(“第二个”);

<代码> > p>您可以使用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"));
#定义替换C(ptr,新值)\
做{\
ptr.reset()\
ptr.重置(新的_值)\
while(假)
独特的c(新的c(“第一个”));
更换_C(C,新的C(“第二个”);

为什么不分配一个新的呢?ptr=make_unique();@paulm:因为他不希望两个实例同时存在。问题是,为什么不能有两个实例,也不能重用现有的一个……这是一种脆弱的方法,在这种方法中,你可能会最终没有任何资源。@DavidRodríguez dribeas我在各种类似istream的对象(ZipEntries)之间切换,它源于单个ZipFile对象(表示包含多个条目的zip存档)。我必须确保在打开新的ZipPentry之前销毁以前的ZipPentry。在我看来,这是一个线程问题,忽略了实际问题。为什么不分配一个新的ZipPentry?ptr=make_unique();@paulm:因为他不希望两个实例同时存在。问题是,为什么不能有两个实例,也不能重用现有的一个……这是一种脆弱的方法,在这种方法中,你可能会最终没有任何资源。@DavidRodríguez dribeas我在各种类似istream的对象(ZipEntries)之间切换,源于单个ZipFile对象(表示包含多个条目的zip存档)。在打开新的ZipEntry之前,我必须确保已销毁以前的ZipEntry。在我看来,这是一个忽略实际问题的线程问题。宏解决方案的可读性令人惊讶,且不易出错:)宏解决方案的可读性令人惊讶,且不易出错:)