【问题标题】:Constructors and operator= with dynamic memory allocation具有动态内存分配的构造函数和运算符 =
【发布时间】:2012-08-22 13:50:35
【问题描述】:

这里是菜鸟。我正在从书中做一个练习,编译器没有报告任何错误,但是当我尝试运行它时程序崩溃了。

我正在尝试运行一个小程序来执行 Cow 类的不同方法。它显式具有:构造函数、默认构造函数、复制构造函数、析构函数、重载赋值运算符和显示其内容的方法。

我会放整个项目:

类规范:

//cow.h -- For project Exercise 12.1.cbp

class Cow
{
    char name[20]; // memory is allocated in the stack
    char *hobby;
    double weight;
public:
    Cow();
    Cow(const char *nm, const char *ho, double wt);
    Cow(const Cow &c);
    ~Cow();
    Cow & operator=(const Cow &c);
    void ShowCow() const; // display all cow data
};

方法实现:

// cow.cpp -- Cow class methods implementation (compile with main.cpp)

#include <cstring>
#include <iostream>
#include "cow.h"

Cow::Cow() // default destructor
{
    strcpy(name, "empty");
    hobby = new char[6]; // makes it compatible with delete[]
    strcpy(hobby, "empty");
    weight = 0.0;
}

Cow::Cow(const char *nm, const char *ho, double wt)
{
    strcpy(name, nm); // name = nm; is wrong, it copies the address of the argument pointer (swallow copying)
    /*if (name[20] != '\0') // if it's not a string, make it a string (in case nm is larger than 20)
        name[20] = '\0';*/
    hobby = new char[strlen(ho) + 1]; // allocates the needed memory to hold the argument string
    strcpy(hobby, ho); // copies the pointed-to data from the argument pointer to the class pointer
    weight = wt;
}

Cow::Cow(const Cow &c) // copy constructor
{
    strcpy(name, c.name); // copies the value to the desired address
    char *temp = hobby; // stores the address of the memory previously allocated with new
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby); // copies the value to the new address
    delete[] temp; // deletes the previously new allocated memory
    weight = c.weight;
}

Cow::~Cow()
{
    delete[] hobby;
}

Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
    strcpy(name, c.name);
    char *temp = hobby;
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby);
    delete[] temp;
    weight = c.weight;
    return *this;
}

void Cow::ShowCow() const
{
    std::cout << "Name: " << name << '\n';
    std::cout << "Hobby: " << hobby << '\n';
    std::cout << "Weight: " << weight << "\n\n";
}

客户:

// main.cpp -- Exercising the Cow class (compile with cow.cpp)

#include "cow.h"
#include <iostream>

int main()
{
    using std::cout;
    using std::cin;

    Cow subject1; // default constructor
    Cow subject2("Maria", "Reading", 120); // non-default constructor
    Cow subject3("Lula", "Cinema", 135);
    subject1 = subject3; // overloaded assignment operator
    Cow subject4 = subject2; // copy constructor
    subject1.ShowCow();
    subject2.ShowCow();
    subject3.ShowCow();
    subject4.ShowCow();

    cin.get();
    return 0;
}

我隐藏了代码的某些部分来定位可能的问题,而程序似乎不喜欢这两行:

subject1 = subject3;
Cow subject4 = subject2

特别是在重载赋值运算符和复制构造函数中,如果我隐藏delete[] temp 行,程序不会崩溃。

我完全是菜鸟,可能有点愚蠢,但我看不出我在这些定义中做错了什么。

有什么帮助吗?

【问题讨论】:

  • 在 C++ 中,您通常不会编写这样的赋值运算符,因为它们与复制构造函数非常相似,因此大多是重复代码。我建议看看Copy and swap idiom
  • @dialer 感谢您的建议!现在,我正在阅读一本真正结构化的书。不过我会看看的。

标签: c++ crash copy-constructor dynamic-memory-allocation assignment-operator


【解决方案1】:
Cow::Cow(const Cow &c) // copy constructor
{
    strcpy(name, c.name); // copies the value to the desired address
    char *temp = hobby; // stores the address of the memory previously allocated with new
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby); // copies the value to the new address
    delete[] temp; // deletes the previously new allocated memory
    weight = c.weight;
}

这是复制品。没有先前分配的成员。 this-&gt;hobby 指向随机垃圾。所以当你delete[] temp(即新分配之前的this-&gt;hobby)时,你会得到UB。

Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
    strcpy(name, c.name);
    char *temp = hobby;
    hobby = new char[strlen(c.hobby) + 1];
    strcpy(hobby, c.hobby);
    delete[] temp;
    hobby = name;
    weight = c.weight;
    return *this;
}

hobby = name 不正确,因为它会导致内存泄漏 + 析构函数会尝试删除未使用 operator new[] 分配的对象。

【讨论】:

  • 感谢您的帮助!确实是一个非常菜鸟的错误,尝试构造函数就好像它是一个赋值运算符。第二个错误是我试图破译我添加代码的错误,该行不应该存在。感谢您的宝贵时间!
【解决方案2】:

@ForEveR 已经注意到您的复制构造函数正在删除从未分配的内存。

但我要争辩说,整个练习是有缺陷的,并且是用类教授 C,而不是 C++。如果您使用字符串,所有问题都会消失,因为您不必直接管理资源。这消除了您完全编写析构函数或复制赋值/构造函数的需要。例如:

class Cow
{
    std::string name;
    std::string hobby;
    double weight;
public:
    Cow();
    Cow(const std::string& nm, const std::string& ho, double wt);
    void ShowCow() const; // display all cow data
};

【讨论】:

  • 感谢您的回答。问题是作者已经知道了。事实上,前面的练习之一涉及创建一个 StringBad 类来模拟(以简化的方式)标准字符串行为。我知道用字符串这一切都过去了,但这只是为了专门练习用类进行动态内存分配。
猜你喜欢
  • 1970-01-01
  • 2017-08-17
  • 1970-01-01
  • 1970-01-01
  • 2014-01-05
  • 2016-07-29
  • 2017-06-25
  • 2011-03-11
  • 2018-04-13
相关资源
最近更新 更多