-2

我遇到了分段错误,我认为这是由复制构造函数引起的。但是,我在网上的任何地方都找不到这样的例子。我读过浅拷贝和深拷贝,但我不确定这个拷贝属于哪个类别。有人知道吗?

MyObject::MyObject{
    lots of things including const and structs, but no pointers
}
MyObject::MyObject( const MyObject& oCopy){
    *this = oCopy;//is this deep or shallow?
}
const MyObject& MyObject::operator=(const MyObject& oRhs){
    if( this != oRhs ){
        members = oRhs.members;
        .....//there is a lot of members
    }
    return *this;
}
MyObject::~MyObject(){
    //there is nothing here
}

代码:

const MyObject * mpoOriginal;//this gets initialized in the constructor

int Main(){
    mpoOriginal = new MyObject();
    return DoSomething();
}

bool DoSomething(){
    MyObject *poCopied = new MyObject(*mpoOriginal);//the copy
    //lots of stuff going on
    delete poCopied;//this causes the crash - can't step into using GDB
    return true;
}

编辑:添加了 operator= 和构造函数

已解决:吠叫错误的树,它最终成为对同一个对象调用两次删除的函数

4

7 回答 7

2

在复制构造函数中使用这样的赋值运算符通常是一个坏主意。这将默认构造所有成员,然后分配给它们。要么只依赖隐式生成的复制构造函数,要么使用成员初始化器列表复制那些需要复制的成员,并将适当的初始化应用于其他成员,这要好得多。

如果没有班级成员的详细信息,很难判断是什么导致了您的段错误。

于 2011-08-25T16:33:11.850 回答
1

根据您的代码,您不是在创建原始对象......您只是在创建一个像这样的指针: const MyObject * mpoOriginal;

所以副本正在使用坏数据到创建的新对象中......

于 2011-08-25T16:32:06.793 回答
0

您正在做的是让您的复制构造函数使用赋值运算符(您似乎没有定义)。坦率地说,我很惊讶它可以编译,但是因为您没有显示所有代码,所以它可能会编译。

用正常的方式编写你的复制构造函数,然后看看你是否仍然遇到同样的问题。如果你所说的“很多事情......但我没有看到任何指针”是真的,那么你根本不应该编写复制构造函数。尝试删除它。

于 2011-08-25T16:32:18.177 回答
0

对于导致段错误的确切原因,我没有直接答案,但这里的传统智慧是遵循三规则,即当您发现自己需要复制构造函数、赋值运算符或析构函数中的任何一个时,您最好实现所有其中三个c++0x添加了移动语义,这使其成为“四规则”?)。

然后,通常是相反的方式 - 复制赋值运算符是根据复制构造函数实现的 -复制和交换习语

于 2011-08-25T16:37:33.823 回答
0
MyObject::MyObject{
    lots of things including const and structs, but no pointers
}

浅拷贝和深拷贝之间的区别只有在存在指向动态内存的指针时才有意义。如果这些成员结构中的任何一个没有对其指针进行深层复制,那么您将不得不解决这个问题(如何取决于结构)。但是,如果所有成员要么不包含指针,要么正确地对其指针进行深拷贝,那么复制构造函数/赋值不是问题的根源。

于 2011-08-25T17:08:28.120 回答
0

哇....

MyObject::MyObject( const MyObject& oCopy)
{
    *this = oCopy;//is this deep or shallow?
}

两者都不是。这是对赋值运算符的调用。
由于您尚未完成对象的构造,因此这可能是不明智的(尽管完全有效)。但是,根据复制构造函数定义赋值运算符更为传统(请参阅复制和交换 idium)。

const MyObject& MyObject::operator=(const MyObject& oRhs)
{
    if( this != oRhs ){
        members = oRhs.members;
        .....//there is a lot of members
    }
    return *this;
}

基本上没问题,虽然通常分配的结果不是续的。
但是如果你这样做,你需要稍微划分你的处理以使其异常安全。它应该看起来更像这样:

const MyObject& MyObject::operator=(const MyObject& oRhs)
{
    if( this == oRhs )
    {
        return *this;
    }
    // Stage 1:
    // Copy all members of oRhs that can throw during copy into temporaries.
    // That way if they do throw you have not destroyed this obbject.

    // Stage 2:
    // Copy anything that can **not** throw from oRhs into this object
    // Use swap on the temporaries to copy them into the object in an exception sage mannor.

    // Stage 3:
    // Free any resources.
    return *this;
}

当然,使用复制和交换 idum 有一种更简单的方法:

MyObject& MyObject::operator=(MyObject oRhs)  // use pass by value to get copy
{
    this.swap(oRhs);
    return *this;
}

void MyObject::swap(MyObject& oRhs)  throws()
{
    // Call swap on each member.
    return *this;
}

如果在析构函数中没有什么可做的,请不要声明它(除非它需要是虚拟的)。

MyObject::~MyObject(){
    //there is nothing here
}

在这里,您声明了一个指针(不是对象),因此不调用构造函数(因为指针没有构造函数)。

const MyObject * mpoOriginal;//this gets initialized in the constructor

在这里,您正在调用 new 来创建对象。
你确定你要这么做吗?必须销毁动态分配的对象;表面上是通过删除,但更常见的是在 C++ 中,您将指针包装在智能指针中,以确保所有者正确并自动销毁对象。

int main()
{ //^^^^   Note main() has a lower case m

    mpoOriginal = new MyObject();
    return DoSomething();
}

但是因为您可能不想要动态对象。您想要的是在超出范围时被销毁的自动对象。此外,您可能不应该使用全局变量(将其作为参数传递,否则您的代码正在使用与全局状态相关的副作用)。

int main()
{
     const MyObject  mpoOriginal;
     return DoSomething(mpoOriginal);
}

您不需要调用 new 来进行复制,只需创建一个对象(传递您要复制的对象)。

bool DoSomething(MyObject const& data)
{
    MyObject   poCopied (data);     //the copy

    //lots of stuff going on
    // No need to delete.
    // delete poCopied;//this causes the crash - can't step into using GDB
    // When it goes out of scope it is auto destroyed (as it is automatic).

    return true;
}
于 2011-08-25T18:28:28.267 回答
-1

两者都可以,这取决于您的operator=工作。这就是魔法发生的地方;复制构造函数只是调用它。

如果您没有operator=自己定义,那么编译器会为您合成一个,它正在执行浅拷贝。

于 2011-08-25T16:31:11.750 回答