在QT里使用QList的时候,如果调用拷贝构造函数或拷贝赋值函数的时候,会报警告
原因
QList继承自QListSpecialMethods,QListSpecialMethods继承自QListSpecialMethodsBase,这两个类显示声明了析构函数,而QList里没有显示声明拷贝构造函数和拷贝赋值函数
在C++11及更高版本中,如果一个类定义了析构函数,编译器仍然会生成默认的拷贝构造函数和拷贝赋值函数,但是这种默认生成的拷贝函数是deprecated性质的,也就是说,它只是一种过渡性的实现,并不推荐使用。编译器认为自定义了析构函数,一般有资源,比如内存资源需要处理,拷贝函数中这些资源最好自定义处理,所以不显示定义拷贝函数,就会报警告。
如下例所示:
//test.h
#ifndef TEST
#define TEST
struct Base {
protected:
~Base();
};
class Derived : public Base {
public:
Derived();
~Derived();
public:
int v = 10;
};
#endif // TEST
//main.cpp
#include "test.h"
int main() {
Derived d1;
Derived d2 = d1;
return 1;
}
c++11以上,编译器会给出警告,不过并不影响正常使用,未来可能新版本不再生成?
QList原理
- 通过函数调用返回QList
代码结构如下:
class Test {
public:
Test(int _v) : v(_v) { cout << "constructor" << endl;
}
~Test() = default;
Test(const Test& test) {
cout << "copy constructor" << endl;
this->v = test.v;
}
Test& operator=(const Test& test) {
if (this != &test) {
cout << "copy assignment" << endl;
this->v = test.v;
}
return *this;
}
int getV() const { return v; }
void setV(int _v) const { const_cast<Test*>(this)->v = _v; }
private:
int v;
};
QList<Test> getList1() {
QList<Test> c;
for (int i = 0; i < COUNT; ++i) {
c.push_back(Test(i));
}
c.at(0).setV(10);
return c;
}
QList<Test> getList2() {
QList<Test> c;
for (int i = 0; i < COUNT; ++i) {
c.push_back(Test(i));
}
c[0].setV(10);
return c;
}
不管内部使用[]还是at,它操作的都是QList c,返回的时候使用QList的默认拷贝构造函数,仅仅是拷贝QList保存的对象的地址,所以不会有性能影响,相比std的容器,速度反而更快(相当于直接使用移动语义)
- 函数内赋值
class Test {
public:
Test(int _v) : v(_v) { cout << "constructor" << endl;
}
~Test() = default;
Test(const Test& test) {
cout << "copy constructor" << endl;
this->v = test.v;
}
Test& operator=(const Test& test) {
if (this != &test) {
cout << "copy assignment" << endl;
this->v = test.v;
}
return *this;
}
int getV() const { return v; }
void setV(int _v) const { const_cast<Test*>(this)->v = _v; }
private:
int v;
};
void useAt() {
QList<Test> c;
for (int i = 0; i < COUNT; ++i) {
c.push_back(Test(i));
}
QList<Test> d = c;
c.at(0).setV(10);
cout << &c.at(0) << "," << c.at(0).getV() << endl; //000001BD74F3E610,10
cout << &d.at(0) << "," << d.at(0).getV() << endl; //000001BD74F3E610,10
}
void useBracket() {
QList<Test> c;
for (int i = 0; i < COUNT; ++i) {
c.push_back(Test(i));
}
QList<Test> d = c;
c[0].setV(10);
cout << &c.at(0) << "," << c.at(0).getV() << endl; //000001BD74F3E670,10
cout << &d.at(0) << "," << d.at(0).getV() << endl; //000001BD74F3DCB0,0
}
使用at进行强行改变的时候,两个QList的元素是共享一份内存数据,所以改变一个的时候,另一个也会被改变,使用[]的时候,QList会调用detach()函数,detach调用reallocateAndGrow,将内存数据拷贝一份(调用对象的拷贝构造函数),所以进行修改的时候,另一个不会被改变。
性能上如果使用[]的话,会慢于at(),毕竟会进行拷贝,所以如果只读的话,建议使用at,读写的话使用[].
at源码:
[]源码:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。