关于析构函数、复制构造函数和赋值运算符的 C++ 练习考试

C++ practice exam on Destructors, Copy Constructors, and Assignment Operators

提问人:Jay 提问时间:7/16/2014 最后编辑:quetzalcoatlJay 更新时间:7/16/2014 访问量:857

问:

这是我明天在 CS 低年级课程的期中模拟考试中的一个问题。不幸的是,模拟考试没有完全正确的解决方案;发布的问题中显示的具体问题在 a)、b) 和 c) 部分各获得了一半的学分。

问题是为什么他们只获得了一半的学分;如果你能为问题的一个或所有部分发布一个完整的解决方案,那将是巨大的价值。

问题如下:


考虑一下这个摘录,摘自一个代表建筑工人的相当普通的班级。

class Worker
{
  public:
    Worker(string nm, string s)
        : m_name(nm), m_skill(s)
    {}
    string name() const { return m_name; }
    string skill() const { return m_skill; }
  private:
    string m_name;
    string m_skill;
};

由于我们没有为 Worker 类声明析构函数、复制构造函数或赋值运算符,因此编译器会为我们编写这些函数。

施工人员是工人的集合。我们选择将 crew 表示为动态分配的指向 Workers 的指针数组。摘录如下:

class Crew
{
  public:
    Crew(int lim)
        : m_size(0), m_maxCrewSize(lim)
    {
        m_crew = new Worker*[lim];
    }

    void hire(string nm, string s)
    {
        if (m_size < m_maxCrewSize)
        {
            m_crew[m_size] = new Worker(nm, s);
            m_size++;
        }
    }
    // other functions not shown
  private:
    Worker** m_crew;
    int m_size;
    int m_maxCrewSize;
};

m_crew 数组的前 m_size 个元素包含指向动态分配的辅助角色的指针;其余元素没有特定值。

Crew 类的用户将需要复制 Crew 对象并将一个 Crew 对象分配给另一个对象。

对于下面的 a、b 和 c 部分,如果您愿意,可以实现其他 Crew 类帮助程序函数。不对 Worker 类进行任何更改或添加。

一个。

完成 Crew 类的析构函数的实现:

Crew::~Crew()
{
  for (int i=0; i<m_size; i++) {
    delete m_crew[i];
  }
}

b.实现 Crew 类的复制构造函数。

Crew::Crew(const Crew& original)
    : m_size(original.m_size), m_maxCrewSize(original.m_maxCrewSize)
{
  m_crew = new Worker*[m_maxCrewSize];
  for (int i=0; i < m_size; i++) {
    m_crew[i] = original.m_crew[i];
  } 
}

c. 实现 Crew 类的赋值运算符。

Crew& Crew::operator=(const Crew& other) {
  if (this != &other) {
    Crew temp(*this);
    m_crew = other.m_crew;
    m_size = other.m_size;
    m_maxCrewSize = other.m_maxCrewSize;
    other.m_crew = temp.m_crew;
    other.m_maxCrewSize = temp.m_maxCrewSize;
    other.m_size = temp.m_size;
  }
  return this;
}
C++ 析构函数 copy-constructor assignment-operator

评论

3赞 quetzalcoatl 7/16/2014
The question is why they received only half-credit- 好吧,问问监督考试和分配分数的人。这就是答案的完美来源。我知道这是无益的,而且是显而易见的,但实际上,没有主管的观点,这主要是猜测(当然,除了一些明显的错误,如果有的话,我没有分析代码 - 我只是对原始问题做出反应)。
0赞 Some programmer dude 7/16/2014
本参考中所述:“如果没有为类类型提供任何类型的用户定义构造函数......编译器将始终将默认构造函数声明为其类的内联公共成员。该段落的意思是,如果类中有任何自定义构造函数,则不会生成默认构造函数。
0赞 PaulMcKenzie 7/16/2014
析构函数不完整。对于m_crew指针本身在哪里?换句话说,执行此操作时未能清理内存:deletem_crew = new Worker*[lim];
0赞 quetzalcoatl 7/16/2014
顺便说一句。在 by 中,如果要进行“试运行”以检查三个部分赋值期间是否有任何异常,则在试运行之后,应按相同的顺序重做赋值。如果您真的在进行试运行,那么在实际运行中更改操作顺序会使试运行结果完全无关紧要。此外,他们的顺序看起来很奇怪。通常,您首先检查最大边界,然后检查实际边界,然后对项目进行操作(但这实际上是惯例和特定于案例的)operator=Crew temp(*this)
0赞 quetzalcoatl 7/16/2014
另一个仅供参考:对于完全不需要的变量进行这样的试运行。此类分配永远不会引发任何错误。你可以简化为简单的三行等待,什么?!你搞砸了它的实现。应该更改为 THIS 并从 OTHER 读取。所以最后三分之一的作业应该是,依此类推。Worker**intoperator=other...operaotr=this->m_crew = other.m_crew

答:

1赞 Joseph Mansfield 7/16/2014 #1
  1. 析构函数不会释放指针数组,这意味着它会泄漏。
  2. 复制构造函数不执行深层复制(这可能是预期的)
  3. 赋值运算符不仅赋值 to ,还赋值 from to 。对于赋值运算符来说,这是完全出乎意料的,它甚至不会编译,因为 是 .otherthisthisotherotherconst

评论

1赞 Joseph Mansfield 7/16/2014
为什么投反对票?阿拉斯泰尔和我独立地提出了相同的反馈。
0赞 quetzalcoatl 7/16/2014
关于 (1):请注意,op= 对 Workers** 进行了浅层赋值,因此 ~dtor 不应解除分配 - 没有人承担所有权。您在 (2) 中介绍了它,但为什么要假设深度复制要求?在某些情况下,制作浅拷贝是完全可以的。恕我直言,太多无法解释的假设,这可能会导致反对票。但是,假设“典型”和“深度”,所有三点都是有效的。最后一个可能是最重要的,我也注意到了。看起来像一个明显的错别字,这可能是考试成绩不好的原因。
0赞 quetzalcoatl 7/16/2014
哦,亲爱的..忘记“所有权”的事情。我刚刚注意到分配数组和项目的 ctor/dtor pait..真是一团糟
1赞 al45tair 7/16/2014 #2

虽然@quetzalcoatl您应该询问标记问题的人为什么这样标记问题,这是正确的,但这里有一些提示:

一个。此答案无法删除数组。结果,内存会泄漏。m_crew

b.在这个答案中,工人本身没有被复制。当新副本或原始对象的析构函数运行时,程序将崩溃,因为双精度 .Crewdelete

c. 这个答案是完全错误的。我不知道为什么有人会给它半分;我什么都不会给。首先,你不能写信,因为它是 .其次,您不应该写信,因为赋值运算符是用于赋值的,而不是交换的。第三,你不能就这样分配,因为它会导致以后因为双精度而崩溃。otherconstotherm_crewdelete

评论

0赞 Jay 7/16/2014
b.但是,Worker 类的复制构造函数不是默认生成的构造函数吗(如问题语句中指定的那样:因为我们没有为 Worker 类声明析构函数、复制构造函数或赋值运算符,所以编译器会为我们编写这些函数。...
0赞 al45tair 7/16/2014
@MattClarkson 或者(更好,IMO)。但是,这是一个考试问题,最好坚持您认为评分方案中可能存在的答案:-)std::vector
0赞 al45tair 7/16/2014
@JayYoon 不过,您不是在复制实例。您只是在复制指向它们的指针。你需要写信才能真正复制它们。Workernew Worker(original.m_crew[i])
0赞 Matt Clarkson 7/16/2014
@alastair,完全同意。只是想指出,如果将来有人在这个答案/问题上胡思乱想,不要把上面的内容作为现代C++编程的例子!