赋值运算符重载问题

时间:2010-06-21 14:02:35

标签: c++ operator-overloading assignment-operator operator-keyword

这个问题让我很困惑。第一段代码工作正常而没有崩溃,它将s1完全分配给s2。但是第二组代码导致程序崩溃。

任何人都知道为什么会发生这种情况或问题是什么?

代码1 :(有效)

    s1.add(10, 30, 25, "Test Screen", false);
s1.add(13, 10, 5, "Name:XXX", false);
s1.add(13, 18, 30);
s1.remove(-1);
Screen s2 = s1;

代码2 :(转让时崩溃)

    Screen s1;

    if (1 != s1.add(10, 30, 25, "Test Screen", false))
        message("first add() has a problem");
   else if (2 != s1.add(13, 10, 5, "Name:XXX", false))
        message("second add() has a problem");
    else if (3 != s1.add(13, 18, 30))
        message("third add() has a problem");
    else if (3 != s1.remove(-1))
       message("first remove() has a problem");
    else {
        Screen s2 = s1;
}

屏幕类的分配运算符:

        Screen& operator=(const Screen &scr) {
        if (this != &scr){
            for (int i = 0; i < 50; i++) {
                if  (fields[i])
                    delete fields[i];
                fields[i] = new LField();
            }

            for (int i = 0; i < scr.numOfFields; i++)
                fields[i] = scr.fields[i];

            numOfFields = scr.numOfFields;
            currentField = scr.currentField;
        }
        return *this;
    }

Field类的赋值运算符:

LField& operator=(const LField &lfieldobj) {
        if (this != &lfieldobj) {

            if (lfieldobj.val) {
                if (val)
                    delete[] val;
                val = new char[strlen(lfieldobj.val) + 1];
                strcpy(val, lfieldobj.val);
            }
            else{
                //val = new char[1];
                val = "";
            }
            rowNum = lfieldobj.rowNum;
            colNum = lfieldobj.colNum;
            width = lfieldobj.width;
            canEdit = lfieldobj.canEdit;
            index = lfieldobj.index;

        }
        return *this;
    }

非常感谢任何输入:)

6 个答案:

答案 0 :(得分:2)

删除当前的val并将其替换为std::string。摆脱fields并将其替换为std::vector。这应该可以消除重载赋值运算符的两个;编译器将提供有效的。我猜你会消除代码中的内存管理问题。

就目前而言,即使您“修复”了解您所知道的内存管理问题,您仍然会面临这样一个事实,即您的代码在异常情况下完全不安全(并使用new因此它基本上无法避免例外情况。)

答案 1 :(得分:2)

        for (int i = 0; i < scr.numOfFields; i++)
            fields[i] = scr.fields[i];

那不行,你正在复制指针而不是指向的值。需要深层复印。

答案 2 :(得分:1)

会员“字段”声明是什么?

LField* fields[50]

如果是,那么谁将左侧对象字段成员初始化为NULL?我会说没有人...赋值运算符就像C ++中的复制构造函数一样,并且你在无效指针上调用delete。

答案 3 :(得分:1)

该行

Screen s2 = s1;

实际上调用Screen复制构造函数,而不是赋值运算符重载。

例如:

#include <iostream>
using namespace std;

class Screen
{
public:
        Screen() { }

        Screen(const Screen& s)
        {
                cout << "in `Screen::Screen(const Screen&)`" << endl;
        }

        Screen& operator=(const Screen& s)
        {
                cout << "in `Screen::operator=(const Screen&)`" << endl;
                return *this;
        }
};

int main()
{
        Screen s1;
        Screen s2 = s1;
}

打印:

  Screen::Screen(const Screen&)

中的

我猜你的Screen拷贝构造函数的定义与Screen::operator=(const Screen&)类似,因此修复赋值运算符重载也可能需要应用于拷贝构造函数定义。

此外,fields Screen成员的定义如何?如果是这样的话:

LField* fields[50];

然后在构造函数中,您必须将数组中的所有LField*对象初始化为NULL,因为它们具有未定义的初始值:

std::fill_n(fields, 50, static_cast<LField*>(NULL));

如果没有此初始化,即使if (fields[i])未指向分配,导致程序尝试i指针,但某些fields[i]的测试delete可能会成功s)未由new返回。

答案 4 :(得分:0)

我设法解决了这个问题。毕竟这是内存分配的一个问题:)

答案 5 :(得分:0)

对于复杂的对象,最好使用复制和交换idum 这为您提供了具有强异常保证(事务安全)的赋值运算符。但这也意味着你只需要在一个地方(构造函数)考虑复杂的对象创建。

Screen& Screen::operator=(Screen const& rhs)
{
    Screen tmp(rhs);
    this->swap(tmp);
    return *this;
}

void Screen::swap(Screen const& rhs) throw ()
{
     // Swap each of the members for this with rhs.
     // Use the same pattern for Field.
}