我有以下内容:
enum Type
{ One = 0, Two};
class MySubClass
{
private:
MySubClass(); // prohibited
MySubClass(const MySubClass&); // prohibited
MySubClass & operator (const MySubClass&); // prohibited
public :
MySubClass(int x);
};
class MyClass
{
MyClass(int x) : m_x(new SubClass(x))
{}
~MyClass()
{ delete m_x; }
private :
MySubClass * m_x;
};
typedef multimap<Type, MyClass> my_multimap;
typedef pair<Type, MyClass> my_pair;
我正在尝试执行以下操作:
my_multimap my_map;
my_map.insert(my_pair(One, MyClass(5)));
我得到一个未处理的异常结果,该应用程序正在尝试读取0xfeeefeee等。
发生了什么事?我怎样才能解决这个问题? 请注意,这是我正在处理的简化案例;
答案 0 :(得分:5)
有一条经验法则,称为“三个规则”:每当你有一个析构函数或赋值运算符或一个复制构造函数时,你很可能需要它们全部三个。您的代码也不例外。
考虑复制类型对象时会发生什么。这个
MyClass obj1;
MyClass obj2(obj1);
代码也会崩溃。
答案 1 :(得分:4)
MyClass
没有定义复制构造函数。但是,std::pair
需要使用MyClass
的复制构造函数。据推测它正在使用MyClass
的默认复制构造函数,它将为复制构造对象提供指针m_x
的副本。当它们被摧毁时,你将面临多次删除。
答案 2 :(得分:1)
你必须写一个复制构造函数。
正在发生的事情是,MyClass是按值复制的 指针在副本之间共享。 现在当物体被摧毁了 指针被删除倍数。
像这样:
class MyClass
{
MyClass(int x) : m_x(new SubClass(x)) {}
MyClass(const MyClass& myclass) : m_x(new SubClass(*myclass.m_x)) {}
~MyClass() { delete m_x; }
private :
MySubClass * m_x;
};
显然,SubClass也需要一个复制构造函数。
答案 3 :(得分:1)
正如大家所提到的,类需要一个工作副本构造函数才能存储在任何标准容器中。但是,在这种情况下,MySubClass禁用复制。这几乎有两个选择:
1)MyClass也应该是不可复制的,在这种情况下你必须在多图中存储(智能)指针。
2)复制的MyClass实例应共享MySubClass实例。要实现这一点,最简单的方法是用boost::shared_ptr<MySubClass>
或std::tr1::shared_ptr<MySubClass>
替换指针成员。这样做可以使您免于执行析构函数,复制构造函数和赋值运算符的任务。