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。在我看来,这是一个忽略实际问题的线程问题。宏解决方案的可读性令人惊讶,且不易出错:)宏解决方案的可读性令人惊讶,且不易出错:)