在某次编译过程中,出现此报错,根据报错日志分析,查明原因,觉得很有意思,于是决定分享出来。
首先,先看例子代码(在main函数中关注test3对象的赋值操作即可,test1和test2对象后面会叙述)
// Example program
#include <iostream>
#include <string>
class NoCopyConstructor {
public:
NoCopyConstructor(){};
~NoCopyConstructor(){};
NoCopyConstructor(const NoCopyConstructor &) = delete; // 拷贝构造函数不可用
// NoCopyConstructor& operator=(const NoCopyConstructor &) = delete; // "="运算符不可用
};
class Test {
public:
Test(){};
~Test(){};
public:
int a;
int b;
NoCopyConstructor noCopyConstructor;
};
Test getTest(int a, int b) {
Test test;
test.a = a;
test.b = b;
return test;
}
int main()
{
Test test1;
test1.a = 1;
test1.b = 2;
Test test2;
test2 = test1;
std::cout << " test2 a = " << test2.a << ", test2 b = "<< test2.b <<"!\n";
Test test3;
test3 = getTest(3, 4);
std::cout << " test3 a = " << test3.a << ", test3 b = "<< test3.b <<"!\n";
}
接着是编译报错日志
main.cpp:27:12: error: call to implicitly-deleted copy constructor of 'Test'
return test;
^~~~
main.cpp:20:23: note: copy constructor of 'Test' is implicitly deleted because field 'noCopyConstructor' has a deleted copy constructor
NoCopyConstructor noCopyConstructor;
^
main.cpp:9:5: note: 'NoCopyConstructor' has been explicitly marked deleted here
NoCopyConstructor(const NoCopyConstructor &) = delete; // 拷贝构造函数不可用
^
1 error generated.
可以看到编译报错的原因是因为在test作为返回值时调用了Test类的默认拷贝构造函数,在拷贝过程中调用了Test类成员对象NoCopyConstructor的拷贝构造函数,但是NoCopyConstructor的拷贝构造函数已经设置为delete,即不可使用,就会出现这个编译报错,切记这个报错和析构函数没有关系。
在实际应用中,通常我们引用的so库对象中,有些类因为某些原因禁止使用拷贝构造函数,我们无法修改so库中的拷贝构造函数的属性,但是可以通过自定义我们当前类的拷贝构造函数来规避问题
针对上面代码,由于NoCopyConstructor并没有被用来处理数据,这时可以修改代码
// Example program
#include <iostream>
#include <string>
class NoCopyConstructor {
public:
NoCopyConstructor(){};
~NoCopyConstructor(){};
NoCopyConstructor(const NoCopyConstructor &) = delete; // 拷贝构造函数不可用
// NoCopyConstructor& operator=(const NoCopyConstructor &) = delete; // "="运算符不可用
};
class Test {
public:
Test(){};
/**
* 重写拷贝构造函数,没有对NoCopyConstructor赋值
*/
Test(const Test& test)
{
this->a = test.a;
this->b = test.b;
}
~Test(){};
public:
int a;
int b;
NoCopyConstructor noCopyConstructor;
};
Test getTest(int a, int b) {
Test test;
test.a = a;
test.b = b;
return test;
}
int main()
{
Test test1;
test1.a = 1;
test1.b = 2;
Test test2;
test2 = test1;
std::cout << " test2 a = " << test2.a << ", test2 b = "<< test2.b <<"!\n";
Test test3;
test3 = getTest(3, 4);
std::cout << " test3 a = " << test3.a << ", test3 b = "<< test3.b <<"!\n";
}
运行结果
test2 a = 1, test2 b = 2!
test3 a = 3, test3 b = 4!
建议关注知识点:默认拷贝构造函数、拷贝构造函数的概念、函数返回值、左值,其他就先不复述了。
再分析个类似编译报错“has a deleted copy assignment operator”
先看代码(这次关注test1和test2对象)
// Example program
#include <iostream>
#include <string>
class NoCopyConstructor {
public:
NoCopyConstructor(){};
~NoCopyConstructor(){};
// NoCopyConstructor(const NoCopyConstructor &) = delete; // 拷贝构造函数不可用
NoCopyConstructor& operator=(const NoCopyConstructor &) = delete; // "="运算符不可用
};
class Test {
public:
Test(){};
Test(const Test& test)
{
this->a = test.a;
this->b = test.b;
}
~Test(){};
public:
int a;
int b;
NoCopyConstructor noCopyConstructor;
};
Test getTest(int a, int b) {
Test test;
test.a = a;
test.b = b;
return test;
}
int main()
{
Test test1;
test1.a = 1;
test1.b = 2;
Test test2;
test2 = test1;
std::cout << " test2 a = " << test2.a << ", test2 b = "<< test2.b <<"!\n";
Test test3;
test3 = getTest(3, 4);
std::cout << " test3 a = " << test3.a << ", test3 b = "<< test3.b <<"!\n";
}
编译报错如下
main.cpp:42:9: error: object of type 'Test' cannot be assigned because its copy assignment operator is implicitly deleted
test2 = test1;
^
main.cpp:25:23: note: copy assignment operator of 'Test' is implicitly deleted because field 'noCopyConstructor' has a deleted copy assignment operator
NoCopyConstructor noCopyConstructor;
^
main.cpp:10:24: note: 'operator=' has been explicitly marked deleted here
NoCopyConstructor& operator=(const NoCopyConstructor &) = delete; // "="运算符不可用
^
main.cpp:46:9: error: object of type 'Test' cannot be assigned because its copy assignment operator is implicitly deleted
test3 = getTest(3, 4);
^
main.cpp:25:23: note: copy assignment operator of 'Test' is implicitly deleted because field 'noCopyConstructor' has a deleted copy assignment operator
NoCopyConstructor noCopyConstructor;
^
main.cpp:10:24: note: 'operator=' has been explicitly marked deleted here
NoCopyConstructor& operator=(const NoCopyConstructor &) = delete; // "="运算符不可用
^
2 errors generated.
根据错误日志可以看出NoCopyConstructor的赋值运算符"="已经设置为delete,即不可使用, 同理解决这个问题,可以自定义我们当前类的赋值运算符"="来规避问题
部分代码如下
class Test {
public:
Test(){};
Test(const Test& test)
{
this->a = test.a;
this->b = test.b;
}
/*
* 重写“=”, 不对NoCopyConstructor赋值
*/
Test& operator=(const Test &test)
{
this->a = test.a;
this->b = test.b;
return *this;
}
~Test(){};
public:
int a;
int b;
NoCopyConstructor noCopyConstructor;
};
最好的解决方案还是在调用Test类赋值过程中,采用指针方式传递,但是要注意指针浅拷贝过程指向的是同一段内存,很有可能在原对象析构时,释放了内存,导致新对象指针调用释放后的内存报错,这就是另一个需要研究的问题了。
写了一篇模棱两可的文章,可能会给大家带来更多困扰,希望能和大家一起讨论,共同进步,献丑了~~~