error: call to implicitly-deleted copy constructor of 编译报错分析

在某次编译过程中,出现此报错,根据报错日志分析,查明原因,觉得很有意思,于是决定分享出来。

首先,先看例子代码(在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类赋值过程中,采用指针方式传递,但是要注意指针浅拷贝过程指向的是同一段内存,很有可能在原对象析构时,释放了内存,导致新对象指针调用释放后的内存报错,这就是另一个需要研究的问题了。

写了一篇模棱两可的文章,可能会给大家带来更多困扰,希望能和大家一起讨论,共同进步,献丑了~~~

这个错误信息是因为 `unordered_set` 中的元素类型 `vector<int>` 并没有默认构造函数。因此,当你创建 `unordered_set<vector<int>>` 类型的对象时,会调用默认构造函数,但由于元素类型没有默认构造函数,所以会报错。 解决方法是使用自定义哈希函数,显式地指定哈希表的大小,或者使用其他支持类型的容器代替 `unordered_set<vector<int>>`。 以下是使用自定义哈希函数的示例代码: ```c++ #include <iostream> #include <unordered_set> #include <vector> struct VectorHash { std::size_t operator()(const std::vector<int>& v) const { std::size_t seed = v.size(); for(auto& i : v) { seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2); } return seed; } }; int main() { std::unordered_set<std::vector<int>, VectorHash> set; set.insert({1, 2, 3}); set.insert({4, 5, 6}); std::cout << set.size() << std::endl; // output: 2 return 0; } ``` 在这个示例中,我们定义了一个名为 `VectorHash` 的结构体,其中包含一个函数调用运算符 `operator()`,用于计算 `vector<int>` 类型的哈希值。在创建 `unordered_set<std::vector<int>, VectorHash>` 类型的对象时,我们将 `VectorHash` 结构体作为第二个模板参数传递给 `unordered_set`,从而使用自定义哈希函数。 需要注意的是,在哈希函数中,我们使用了一种叫做 MurmurHash 的哈希算法来计算哈希值。这是一种比较高效的哈希算法,可以参考相关文献了解更多细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值