【问题标题】:use of deleted function 'constexpr class_name& class_name::operator=(const class_name&)'使用已删除的函数 'constexpr class_name& class_name::operator=(const class_name&)'
【发布时间】:2021-12-26 15:49:29
【问题描述】:

作为初学者挑战练习,我正在尝试实现以下内容: 具有属性 (Vec_ptr_cls) 的类:指向向量的指针,方法:构造函数、复制构造函数、移动构造函数、析构函数和 push_back 方法,因为指针是私有的。 具有属性的类 (Data_cls):指向 int 的指针,方法:构造函数、复制构造函数、移动构造函数和析构函数。

预期结果:程序编译,创建 Data_cls 的新对象。创建 Vec_ptr_cls 的新对象,将创建的 Data_cls 对象推回。 实际结果:程序无法编译。错误信息:使用已删除的函数 'constexpr Data_cls& Data_cls::operator=(const Data_cls&)'。

我已经尝试在 StackOverflow 上搜索并检查答案,我认为要么我没有必要的知识来理解它们,要么它们不适用于这种特殊情况(它们中的大多数与 const 属性有关一些课程,据我所知,我没有)。我试图剪掉一些零碎的东西,似乎 Data_cls 的移动构造函数有问题,但我不明白为什么或如何。编译器错误声称复制构造函数已被删除,但是我已经声明了自己的,这还不够好吗?编辑:正如 Nathan Pierson 所指出的,编译器实际上是在抱怨赋值运算符,而不是复制构造函数。我在这里更难过。

这是复制我遇到的问题的原型代码:

#include <iostream>
#include <vector>

class Data_cls
{
private:
    int *d;
public:
    Data_cls(int num)
    {
        d = new int;
        *d = num;
    }

    Data_cls(const Data_cls &source)
    {
        d = new int;
        *d = *source.d;
    }

    Data_cls(Data_cls &&source)
    {
        d = source.d;
        source.d = nullptr;
    }

    ~Data_cls()
    {
        delete d;
    }
};


class Vec_ptr_cls
{
private:
    std::vector <Data_cls> *vec;

public:
    Vec_ptr_cls()
    {
        vec = new std::vector <Data_cls>;
        *vec = {};
    }

    Vec_ptr_cls(const Vec_ptr_cls &source)
    {
        vec = new std::vector <Data_cls>;
        *vec = *source.vec;
    }

    Vec_ptr_cls(Vec_ptr_cls &&source)
    {
        vec = source.vec;
        source.vec = nullptr;
    }

    ~Vec_ptr_cls()
    {
        delete vec;
    }

    void add_new(Data_cls d)
    {
        (*vec).push_back(d);
    }


};

int main()
{

    Data_cls test_d{20};
    Data_cls test_dd{30};
    Data_cls test_ddd{40};

    Vec_ptr_cls tmp_vec{};

    tmp_vec.add_new(test_d);
    tmp_vec.add_new(test_dd);
    tmp_vec.add_new(test_ddd);


    return 0;

}

我在尝试实现一些更复杂的东西(电影列表和电影对象)作为练习时遇到了这个问题,我发现有趣的是,即使简化为这个简单的版本,它也不起作用。我希望我的问题没有说得不好,很好奇为什么这不起作用。

【问题讨论】:

  • 你的 C++ 教科书的章节主题是什么?了解正在学习的主题将有助于指出问题所在。
  • Tangential: delete[] vec; in ~Vec_ptr_cls 不正确。你没有使用new[]创建vec,你不应该使用delete[]来销毁它。
  • 另外编译器错误不是抱怨副本 constructor 被删除,而是抱怨副本 assignment operator 被删除。
  • @SamVarshavchik 这是关于类和对象的一般章节。这一章还介绍了构造函数、复制构造函数和移动构造函数(这是 Tim Buchalka 的 Udemy 课程)。没有指针,这就是本章练习的结尾。在解决方案视频的最后,讲师提出了一个挑战,即用指针作为属性而不是非 ptr 数据类型来重新制作整个练习。 @NathanPierson 啊,谢谢,没错,我应该使用 delete。在赋值运算符部分,嗯,这是正确的,我的错误。
  • "[class.copy.assign]/2 ... 如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符定义为删除..." 由于您已经为您的类提供了一个移动构造函数,因此您还必须提供一个复制赋值运算符;并且可能还想提供移动分配。

标签: c++ class pointers vector move-constructor


【解决方案1】:

Igor Tandetnik 指出这是一个缺少复制赋值运算符的情况,我不知道它存在。添加这个解决了这个问题,程序编译并按预期工作。

#include <iostream>
#include <vector>


class Data_cls
{
private:
    int *d;
public:
    Data_cls(int num)
    {
        d = new int;
        *d = num;
    }

    Data_cls(const Data_cls &source)
    {
        d = new int;
        *d = *source.d;
    }

    Data_cls(Data_cls &&source)
    {
        d = source.d;
        source.d = nullptr;
    }


// Added this assignment operator

    Data_cls& operator=(Data_cls other)
    {
        std::swap(d, other.d);
        return *this;
    }

    ~Data_cls()
    {
        delete d;
    }

    void display()
    {
        std::cout << *d;
    }
};


class Vec_ptr_cls
{
private:
    std::vector <Data_cls> *vec;

public:
    Vec_ptr_cls()
    {
        vec = new std::vector <Data_cls>;
        *vec = {};
    }

    Vec_ptr_cls(const Vec_ptr_cls &source)
    {
        vec = new std::vector <Data_cls>;
        *vec = *source.vec;
    }

    Vec_ptr_cls(Vec_ptr_cls &&source)
    {
        vec = source.vec;
        source.vec = nullptr;
    }

    ~Vec_ptr_cls()
    {
        delete vec;
    }

    void add_new(Data_cls d)
    {
        (*vec).push_back(d);
        d.display();
    }

};

int main()
{

    Data_cls test_d{20};
    Data_cls test_dd{30};
    Data_cls test_ddd{40};

    Vec_ptr_cls tmp_vec{};

    tmp_vec.add_new(test_d);
    tmp_vec.add_new(test_dd);
    tmp_vec.add_new(test_ddd);


    return 0;

}

谢谢大家!

【讨论】:

  • 对问题的回答应充分体现解决方案。在确认某项工作有效的情况下,我会建议对帮助您的解决方案发表评论并进行投票。
  • @user904963 感谢您的建议,我已经添加了带有注释的代码。如果我错了,请纠正我,但是我认为我需要 15 个代表来支持 cmets,这确实是我在 StackOverflow 上的第一篇文章。要让我投票,解决我问题的人必须代替我回答问题,对吗?
猜你喜欢
  • 1970-01-01
  • 2021-07-28
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 2013-08-11
  • 1970-01-01
  • 2017-04-29
相关资源
最近更新 更多