我正在使用std :: unique_ptr在类上创建一些公共成员,这些成员必须是不可复制的或可移动的。但是std :: unique_ptr是可移动的,我想知道如果有人移动std :: unique_ptr包含的指针然后我尝试访问被移动的那个类的std :: unique_ptr成员会发生什么。
示例代码:
#include <cstdlib>
#include <memory>
#include <string>
#include <iostream>
struct obj
{
obj(std::string id)
: id(id)
{
}
void identif()
{
std::cout << "i am " << id << std::endl;
}
std::string id;
};
struct objs
{
// They must stay here no mater what.
std::unique_ptr< obj > obj_a;
std::unique_ptr< obj > obj_b;
std::unique_ptr< obj > obj_c;
objs()
: obj_a(std::unique_ptr< obj >( new obj("object a") ))
,obj_b(std::unique_ptr< obj >( new obj("object b") ))
,obj_c(std::unique_ptr< obj >( new obj("object c") ))
{
}
void do_a()
{
std::cout << " member: " << obj_a->id << std::endl;
std::cout << " method: ";
obj_a->identif();
}
void do_b()
{
std::cout << " member: " << obj_b->id << std::endl;
std::cout << " method: ";
obj_b->identif();
}
void do_c()
{
std::cout << " member: " << obj_c->id << std::endl;
std::cout << " method: ";
obj_c->identif();
}
};
int main(int argc, char** argv)
{
objs obx;
std::cout << " before move: " << std::endl;
obx.do_a();
obx.do_b();
obx.do_c();
std::cout << " after move: " << std::endl;
std::unique_ptr< obj > newb(std::move(obx.obj_b));
obx.do_a();
obx.do_b();
obx.do_c();
return EXIT_SUCCESS;
}
应用程序崩溃,因为当然导致我的问题。我怎样才能防范这种情况?
对象必须是公共的,不是常量,不能移动或复制。有问题的实际对象使用可变参数模板,我宁愿不使用旧方法在obj中使用静态成员函数create(),然后保护构造函数。 此外,我需要避免使用geters和setter,因为该类使用了可变参数模板并使代码变得难看。
我只需要使std :: unique_ptr不可移动,并简单地保存一个不能从拥有它的类中移动或复制的唯一指针。
有问题的实际代码是来自Nano-signal-slot库的Nano :: signal类。 (如果有人需要实际代码)
编辑: 适应使用Nevin的方法并使其工作。我发布了代码,因为Nevin在容器而不是对象上实现它。
#include <cstdlib>
#include <memory>
#include <string>
#include <iostream>
struct obj
{
obj(std::string id)
: id(id)
{
}
obj(obj const&) = delete;
obj& operator=(obj const&) = delete;
obj& operator=(obj&&) = delete;
obj(obj&&) = delete;
void identif()
{
std::cout << "i am " << id << std::endl;
}
std::string id;
};
struct objs
{
const std::unique_ptr< obj > obj_a;
const std::unique_ptr< obj > obj_b;
const std::unique_ptr< obj > obj_c;
objs()
: obj_a(std::unique_ptr< obj >( new obj("object a") ))
,obj_b(std::unique_ptr< obj >( new obj("object b") ))
,obj_c(std::unique_ptr< obj >( new obj("object c") ))
{
}
void do_a()
{
std::cout << " member: " << obj_a->id << std::endl;
std::cout << " method: ";
obj_a->identif();
}
void do_b()
{
std::cout << " member: " << obj_b->id << std::endl;
std::cout << " method: ";
obj_b->identif();
}
void do_c()
{
std::cout << " member: " << obj_c->id << std::endl;
std::cout << " method: ";
obj_c->identif();
}
};
int main(int argc, char** argv)
{
objs obx;
std::cout << " before move: " << std::endl;
obx.do_a();
obx.do_b();
obx.do_c();
std::cout << " after move: " << std::endl;
std::unique_ptr< obj > newb(std::move(obx.obj_b));
obx.do_a();
obx.do_b();
obx.do_c();
return EXIT_SUCCESS;
}
现在应该生成:
main.cpp: In function 'int main(int, char**)':
main.cpp:77:53: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = obj; _Dp = std::default_delete<obj>]'
std::unique_ptr< obj > newb(std::move(obx.obj_b));
^
In file included from /usr/include/c++/4.8/memory:81:0,
from main.cpp:2:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
答案 0 :(得分:5)
只需使objs
不可复制且不可移动,如:
struct objs
{
objs(objs const&) = delete;
objs& operator=(objs const&) = delete;
objs& operator=(objs&&) = delete;
objs(objs&&) = delete;
std::unique_ptr< obj > obj_a;
std::unique_ptr< obj > obj_b;
std::unique_ptr< obj > obj_c;
objs()
: obj_a(std::unique_ptr< obj >( new obj("object a") ))
,obj_b(std::unique_ptr< obj >( new obj("object b") ))
,obj_c(std::unique_ptr< obj >( new obj("object c") ))
{}
};
另外,一旦你完成了这项工作,内部也不需要指针。您可以将代码简化为:
struct objs
{
objs(objs const&) = delete;
objs& operator=(objs const&) = delete;
objs& operator=(objs&&) = delete;
objs(objs&&) = delete;
obj obj_a;
obj obj_b;
obj obj_c;
objs()
: obj_a("object a")
,obj_b("object b")
,obj_c("object c")
{}
};
答案 1 :(得分:0)
newb(std::move(obx.obj_b))
此代码预计会使obx
处于未指定状态,因此您不应尝试再次访问它,而应尝试访问newb
。如果您不希望移动包含的unique_ptr
,则不要移动其容器obx
。或者,如果要定义(或禁用)移动struct objs
的语义,则提供自己的移动构造函数(赋值等)或删除默认值(取决于您要执行的操作)