创建Foo
的实例时,将传递对象oMyClass
并调用其复制构造函数。
MyClass有一个void指针作为成员,指向在dtor中释放的内存。
如何在同一内存中调用free()
两次时,如何正确实现复制构造函数以避免分段错误?
这是我的代码:
int main(int argc, char* argv[])
{
MyClass oMyClass();
Foo oFoo(oMyClass);
}
class MyClass
{
public:
MyClass()
{
struct foo *pFoo;
buf = malloc(sizeof(*pFoo));
}
MyClass::MyClass(const MyClass& oMyClass)
{
printf("Copyconstructor called\n");
//?
}
MyClass::~MyClass()
{
struct foo *pFoo = (struct foo *)buf;
free(pFoo);
}
private:
void* buf;
};
/*Foo.h*/
class Foo
{
public:
Foo( MyClass& oMyClass);
Foo();
~Foo();
private:
MyClass m_oMyClass;
};
/*Foo.cpp*/
Foo::Foo( MyClass& oMyClass): m_oMyClass(oMyClass)
{
}
Foo::Foo()
{
}
答案 0 :(得分:4)
根本不要写一个复制构造函数(参见Rule of Zero)。
相反,依靠带有自定义删除程序的智能指针为您执行资源管理。 unique_ptr
将为您提供可移动的所有权,shared_ptr
将为您提供共享所有权:
void* data = malloc(sizeof(*pFoo));
// either
std::unique_ptr<void, void(*)(void*)> foo(data, free);
// or
std::shared_ptr<void> foo(data, free);
只有当你真的想要执行所附数据的深层复制时,你才需要编写一个复制构造函数(但在这种情况下你仍然可以free
执行const unique_ptr
答案 1 :(得分:1)
你必须复制数据(或保留一个引用计数,只有在引用它的最后一个对象被销毁时才释放数据 - 但如果数据是可变的,这几乎肯定不是你想要的那样。)
MyClass::MyClass(const MyClass& oMyClass)
{
buf = malloc(sizeof(foo));
memcpy(buf, oMyClass.buf, sizeof(foo));
// or new(buf) foo(*reinterpret_cast<foo*>(oMyClass.buf));
}
如果您使用普通new
/ delete
代替malloc
/ free
,则可以免费获得foo
的副本构造函数。 ..
答案 2 :(得分:1)
当您在此处复制构造时,您需要创建自己的构造项目的方式。
“默认”是简单地将项目复制到新项目。这就是为你提供seg-fault的原因,因为当正常复制时,指向foo的指针在两个地方都是相同的。然后,当破坏时,你释放两次相同的记忆。
因此,在复制构造函数中,您需要分配新内存,并复制内存的内容:
MyClass::MyClass(const MyClass& oMyClass)
{
buf = malloc(sizeof(foo));
memcpy(buf, oMyClass.foo, sizeof(foo));
printf("Copyconstructor called\n");
//?
}
答案 3 :(得分:1)
问题就在这里 - 你想要发生什么?
您可以共享两个类之间的内存,也可以复制内存。
理想情况下,使用std::shared_ptr
或boost::shared_ptr
这样的类会自动为您执行引用计数。如果您想自己进行引用计数,则必须使用编译器中可用的原子内在函数,并使用整数malloced来跟踪引用计数。
您可以使用std::memcpy
将内存复制到新分配的内存中:
MyClass::MyClass(const MyClass& other)
: buf(malloc(sizeof(*buf)) {
if (!buf) {
throw std:bad_alloc();
}
std::memcpy(buf, other.buf, sizeof(*buf));
}