【问题标题】:assignment operator overloading problem赋值运算符重载问题
【发布时间】:2011-03-06 08:16:22
【问题描述】:

这个问题让我很困惑。第一段代码可以正常工作而不会崩溃,它将 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;
    }

字段类的赋值运算符:

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;
    }

任何意见将不胜感激:)

【问题讨论】:

  • 没有看到赋值运算符定义,这很可能无法回答。
  • 您确定它会在作业中崩溃吗? s2 一创建就会超出范围,所以可能是析构函数的问题?
  • 我添加了赋值运算符定义。我是积极的克里斯,在崩溃的代码中,我已经注释掉了分配并且它工作正常。
  • 尝试不使用析构函数的赋值。屏幕 &s2(*(新屏幕)); s2 = s1;也许
  • 如果您的复制构造函数很好,则使用复制和交换 idum 作为赋值运算符。您当前使用的方法不提供异常安全性(如果分配出错,您当前无法对对象提供任何保证)。

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


【解决方案1】:

摆脱您当前的val 并将其替换为std::string。摆脱您的 fields 并将其替换为 std::vector。这应该可以让您消除 both 重载的赋值运算符;编译器将提供那些可以工作的。我猜你会连同代码一起消除内存管理问题。

就目前而言,即使您“修复”了您所知道的内存管理问题,您也将面临这样一个事实,即您的代码在面对异常时完全不安全(并且使用new 所以基本也避免不了异常)。

【讨论】:

    【解决方案2】:
            for (int i = 0; i < scr.numOfFields; i++)
                fields[i] = scr.fields[i];
    

    这不行,您复制的是指针而不是指向的值。需要深拷贝。

    【讨论】:

      【解决方案3】:

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

      LField* fields[50]?

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

      【讨论】:

        【解决方案4】:

        线

        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&amp;)

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

        另外,Screenfields 成员是如何定义的?如果是这样:

        LField* fields[50];
        

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

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

        如果没有这个初始化,测试if (fields[i]) 可能会成功一些i,即使fields[i] 没有指向分配,导致您的程序尝试delete 不是由@ 返回的指针987654337@.

        【讨论】:

          【解决方案5】:

          我已经设法修复它。毕竟这是内存分配的问题:)

          【讨论】:

          • 可能是这样,但您的代码根本没有调用赋值运算符。错误在你的复制构造函数中——你也需要纠正它。
          • 并按照 Jerry 的建议删除所有新的和删除的内容
          【解决方案6】:

          对于复杂的对象,最好使用复制和交换 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.
          }
          

          【讨论】:

            猜你喜欢
            • 2019-08-09
            • 1970-01-01
            • 1970-01-01
            • 2013-03-30
            • 2013-02-14
            • 2016-08-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多