一个关于QList类型实例拷贝构造函数的奇怪问题

3
以下是代码概述,用于演示问题。感谢您的时间。
1. 在 "RowOfData rowData = tableData[row];" 处,将调用 RowOfData 的复制构造函数并执行浅拷贝。
2. 在 "tableData[row][col] = item;" 处,会由 tableData[row][col] 赋值操作调用 QtParameter 的复制构造函数,并接着调用 QList::node_copy,以便分配新条目 tableData[row][col]。
问题:
为什么 tableData[row][col] 会调用 QtParameter 的复制构造函数?
顺便说一下,在函数结束时析构 rowData 时,不会为 tableData[row][col] 调用 QtParameter 的复制构造函数。
类:
            QtParameter::QtParameter( const QtParameter& rhs) :QVariant(rhs){}

            class RowOfData : QList<QtParameter>
            {
               public:
                  RowOfData(const RowOfData& rhs);                 
               private:            
            }

            class TableData
            {
               public :
                    TableData();
                    virtual ~TableData();
                    bool setItem(int row, int col, QtParameter item);                    
              protected:
                    QStringList         columnHeader;
                    QStringList         rowHeader;
                    QStringList         rowFooter;
                    QList< RowOfData >  tableData;              
            }    

成员函数:

           bool TableData::setItem(int row, int col, QtParameter item)
           {
              if(row<rowCount())     
               {                
                    RowOfData rowData = tableData[row];
            /*useless here and impact the tableData[row][col] copy constructer× */            
                    if( col < tableData.at(row).size() )
                    {
                        tableData[row][col] = item;
                    }
                }
            } 
            template <typename T>
            Q_INLINE_TEMPLATE void QList<T>::node_copy(Node *from, Node *to, Node *src)
            {
                Node *current = from;
                if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) {
                    QT_TRY {
                        while(current != to) {
                            current->v = new T(*reinterpret_cast<T*>(src->v));
                            ++current;
                            ++src;
                        }
                    } QT_CATCH(...) {
                        while (current-- != from)
                            delete reinterpret_cast<T*>(current->v);
                        QT_RETHROW;
                    }
            ...
            }


我正在考虑在QList中使用"tableData[row][col]"的[]操作是否会触发深拷贝。然而问题是,为什么在删除"RowOfData rowData = tableData[row];"后,就没有深拷贝操作了。 - water
我写了一个答案。如果它解决了问题,请考虑投票/接受它!(https://stackoverflow.com/help/someone-answers) - AKL
1个回答

1
QtParameter 类型的对象调用成员函数 TableData::setItem 时,可能会出现一种情况。由于该函数没有采用引用方式进行传递,所以在函数内部必须通过从之前的对象复制构造来创建一个 QtParameter 类型的对象!
如果要避免这种情况,应该采用引用方式(最好是 const 引用)来传递。
bool TableData::setItem(int row, int col, const QtParameter& item)

往前看,在以下函数内部:

RowOfData rowData = tableData[row];

如果这些不是某种迭代器/指针的最低级别,那么这也可能是源头。

最后在:

tableData[row][col] = item;

根据您提到的内容,另一个可能性是tableData[row][col]类的赋值运算符本身的定义方式。 请记住,赋值运算符也是一个函数,如果它没有声明如下:
assigned_to & operator=(const assigned_from &)

例如:

assigned_to & operator=(assigned_from)

与第一种情况相同,一个assigned_from对象将在赋值运算符内进行复制构造。

许多信息未提供,如果您正在引用的“深拷贝”,则复制构造函数也可以在其中简单地进行:

current->v = new T(*reinterpret_cast<T*>(src->v));

这是一个明确调用复制构造函数的信号。但由于没有提供有关类型的信息,我无法确定是否调用了该复制构造函数。
此外,除非您提供有关“ QList<QtParameter> ”的信息,否则我无法说明为什么在销毁“ rowData”时未进行“深度复制”。

感谢您的回复,@AKL,仍有一些不清楚的地方:1)实际上,在进入函数时才会为item对象进行复制构造,2)在=操作之前对tableData [row]进行深度复制,3)为什么在删除RowOfData rowData = tableData [row]时不进行深度复制操作。顺便说一句,我尝试使用引用,问题仍然存在。 - water
嗨Akl,现在我正在考虑为什么添加RowOfData rowData = tableData[row]会导致tableData[row]进行深拷贝,我有一个假设并不确定,因为RowOfData rowData = tableData[row]会调用复制构造函数,并且它是浅拷贝,当退出函数时rowData将释放其内存,编译器可能会让tableData[row]进行深拷贝,否则动态内存将被释放。我认为这取决于编译器,但我不确定。 - water
@water,请尝试使用RowOfData rowData(std::move(ableData[row]));。并且需要包含头文件#include <utility> - AKL
both rowData = std::move(tableData[row]) , RowOfData rowData(std::move(ableData[row])); 会调用 RowOfData::RowOfData(const RowOfData& rhs) 拷贝构造函数,问题仍然存在,感谢您的建议。 - water
@water 你的意思是说“代码是私有的”,对吗? :) 很高兴听到你自己找到了问题并解决了它,干得好。如果我的回答对你有帮助或启发,请至少给我投一票表示感谢(请 :) ) - AKL
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接