【问题标题】:How do I return results while using operator overloading +使用运算符重载时如何返回结果 +
【发布时间】:2020-11-06 16:33:40
【问题描述】:

当我使用运算符重载并返回临时对象时,我的代码让我感到困惑,它调用了我的复制构造函数并且我遇到了异常,但是当我返回我的类成员 temp.size 时,它​​调用了我的参数化构造函数MyClass(int size) 一切正常。我对它的工作原理以及与之相关的内容很感兴趣。代码如下。

class MyClass
{
private:
    int* data;
    int size;
    
public:
    MyClass()
    {
        size = 0;
    }
    MyClass(int size)
    {
        this->size = size;
        data = new int[size];
        for (size_t i = 0; i < size; i++)
        {
            data[i] = rand();
        }
    }
    MyClass(const MyClass& obj)
    {
        this->size = obj.size;
        this->data = new int[size];
        for (size_t i = 0; i < size; i++)
        {
            data[i] = obj.data[i];
        }
    }
    MyClass operator+(const MyClass& obj)
    {
        MyClass temp;
        temp.size = this->size + obj.size;
        return temp.size;
    }
    friend ostream& operator<<(ostream& os, MyClass& obj);

    ~MyClass()
    {
        delete[]data;
    }
};

ostream& operator<<(ostream & os, MyClass & obj)
{
    os << obj.size;
    return os;
}

int main()
{
    MyClass a(5);
    MyClass b(a);
    MyClass c = a + b;
    cout << c;
    return 0;
}

【问题讨论】:

  • 他们在问题的开头声明这会导致他们出现异常。但是,当我运行它时,它不会导致我出现异常。我得到相反的结果。复制构造函数没有异常,但大小构造函数确实出现异常。
  • 它在销毁临时MyClass时导致崩溃,因为默认构造函数不会new数据,而是delete它。
  • 问题是什么?
  • 你应该在默认构造函数上将data设置为nullptr,然后在析构函数中删除之前检查它不是nullptr
  • obj.data 不存在,因为你没有调用new

标签: c++ class polymorphism operator-overloading


【解决方案1】:

我发现您的代码存在几个问题:

  • 您的默认构造函数未初始化 data

  • 您的 operator+ 未尝试将值从 this-&gt;dataobj.data 复制到 temp.data,因此未初始化 temp.data

  • 您的 operator+ 返回错误的 MyClass 对象。它很麻烦地准备了一个名为tempMyClass 对象,然后在退出时完全丢弃temp。通过将temp.size 传递给return,您将通过MyClass(int size) 构造函数创建另一个 MyClass 对象,该构造函数会生成所有新的随机数据。您需要将 return 替换为您准备的 temp 对象。然后编译器将调用您的复制构造函数将temp 分配给main() 中的c,或者将optimize away the copyoperator+ 直接对c 进行操作。

  • 根据Rule of 3,您缺少一个复制赋值运算符。您的示例中没有任何内容实际调用复制分配,但您仍然需要正确实现运算符。如果您使用 C++11 或更高版本,您还应该遵循 Rule of 5,添加移动构造函数和移动赋值运算符。但是,如果您可以将设计更改为使用std::vector 而不是new[],那么您可以按照Rule of 0 并让编译器为您完成所有艰苦的工作。

话虽如此,请尝试更多类似的东西:

#include <iostream>
#include <algorithm>
#include <utility> // C++11 and later only...
#include <cstdlib>
#include <ctime>    

class MyClass
{
private:
    int* data;
    size_t size;
    
public:
    MyClass(size_t size = 0) : data(NULL), size(size)
    {
        if (size > 0)
        {
            data = new int[size];
            // in C++11 and later, consider using std::uniform_int_distribution instead of rand()!
            std::generate(data, data + size, std::rand);
        }
    }

    MyClass(const MyClass& obj) : data(NULL), size(obj.size)
    {
        if (size > 0)
        {
            data = new int[size];
            std::copy(obj.data, obj.data + obj.size, data);
        }
    }

    // C++11 and later only...
    MyClass(MyClass&& obj) : data(NULL), size(0)
    {
        std::swap(size, obj.size);
        std::swap(data, obj.data);
    }

    ~MyClass()
    {
        delete[] data;
    }

    MyClass& operator=(const MyClass& rhs)
    {
        if (&rhs != this)
        {
            MyClass temp(rhs);
            std::swap(size, temp.size);
            std::swap(data, temp.data);
        }
        return *this;
    }
    
    MyClass& operator=(MyClass&& rhs)
    {
        MyClass temp(std::move(rhs));
        std::swap(size, temp.size);
        std::swap(data, temp.data);
        return *this;
    }

    MyClass operator+(const MyClass& obj) const
    {
        MyClass temp;
        temp.size = size + obj.size;
        if (temp.size > 0)
        {
            temp.data = new int[temp.size];
            std::copy(data, data + size, temp.data);
            std::copy(obj.data, obj.data + obj.size, temp.data + size);
        }
        return temp;
    }

    friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
};

std::ostream& operator<<(std::ostream& os, const MyClass& obj)
{
    os << obj.size;
    for(size_t i = 0; i < obj.size; ++i)
    {
        os << " " << obj.data[i];
    }
    return os;
}

int main()
{
    std::srand(std::time(0));
    MyClass a(5);
    MyClass b(a);
    MyClass c = a + b;
    std::cout << c;
    return 0;
}

可以简化为:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

class MyClass
{
private:
    std::vector<int> data;
    
public:
    MyClass(size_t size = 0) : data(size)
    {
        std::generate(data.begin(), data.end(), std::rand);
    }

    MyClass operator+(const MyClass& obj) const
    {
        MyClass temp;
        if (!data.empty() || !obj.data.empty())
        {
            temp.data.reserve(data.size() + obj.data.size());
            temp.data.insert(temp.data.end(), data.begin(), data.end());
            temp.data.insert(temp.data.end(), obj.data.begin(), obj.data.end());
        }
        return temp;
    }

    friend std::ostream& operator<<(std::ostream& os, const MyClass& obj);
};

std::ostream& operator<<(std::ostream& os, const MyClass& obj)
{
    os << obj.size;
    for(size_t i = 0; i < obj.size; ++i)
    {
        os << " " << obj.data[i];
    }
    return os;
}

int main()
{
    std::srand(std::time(0));
    MyClass a(5);
    MyClass b(a);
    MyClass c = a + b;
    std::cout << c;
    return 0;
}

【讨论】:

    【解决方案2】:

    如果你可以使用std::vector,你的代码可以变成:

    class MyClass {
    private:
        vector<int> data;
    public:
        MyClass(int size) {
            data.resize(size);
            for (size_t i = 0; i < size; i++) {
                data[i] = rand();
            }
        }
        MyClass operator+(const MyClass& obj) {
            return data.size() + obj.data.size();
        }
        friend ostream& operator<<(ostream& os, MyClass& obj);
    };
    
    ostream& operator<<(ostream& os, MyClass& obj) {
        os << obj.data.size();
        return os;
    }
    

    否则不要在未初始化的指针上delete。 (所以要么调用new 或设置为nullptr)。 你没有在默认构造函数中初始化指针,所以不要在析构函数中调用delete。 更改默认构造函数,将data 设置为nullptr

        MyClass() {
            data = nullptr;
            size = 0;
        }
    

    当您没有初始化指针时,也不要从数组中复制。当您设置 size 变量时,您并没有创建数组。您应该创建一个名为setSize 的函数并将您的代码更改为:

        MyClass(int size) {
            data = nullptr;
            setSize(size);
        }
        void setSize(int size) {
            this->size = size;
            delete[] data;
            data = new int[size];
            for (size_t i = 0; i < size; i++) {
                data[i] = rand();
            }
        }
        MyClass operator+(const MyClass& obj) {
            MyClass temp;
            temp.setSize(this->size + obj.size);
            return temp.size;
        }
    

    当您需要更改大小时,您应该使用setSize 函数来确保也创建了数组。

    【讨论】:

    • "在删除之前检查数据是否为 ​​nullptr" - 你不需要这样做。 delete 可以安全地在空指针上调用。
    • @RemyLebeau 我不知道,谢谢你提供的信息。我已经更新了答案,删除了对 nullptr 的检查。
    猜你喜欢
    • 1970-01-01
    • 2020-05-12
    • 2020-07-09
    • 1970-01-01
    • 2013-06-01
    • 2021-05-12
    • 2015-05-19
    • 2015-01-29
    • 1970-01-01
    相关资源
    最近更新 更多