【问题标题】:Difference between , and ;?, 和; 之间的区别?
【发布时间】:2018-01-18 15:39:08
【问题描述】:

编辑 看来我没有很好地解释自己。我的问题不是关于 3 规则,或者如何以一种好的方式实施它。我的问题是为什么在使用逗号时析构函数在完成序列后调用,而不是在变量离开范围时调用,我的意思是,只有当逗号之间的所有函数都完成时,对象才会被销毁,你可以看到它为析构函数添加了一个 cout。

在这个例子中,

#include <iostream>    
#include <cstring>    
using namespace std;    

class Libro {    
 char* titulo_; int paginas_;    
 public:    
 Libro() : titulo_(new char[1]), paginas_(0) {*titulo_= 0;}    
 Libro(const char* t, int p) : paginas_(p) {    
  titulo_ = new char[strlen(t) + 1];    
  strcpy(titulo_, t);    
}    
 ~Libro() { delete[] titulo_; }    
 void paginas(int p) { paginas_ = p; }    
 int paginas() const { return paginas_; }    
 char* titulo() const { return titulo_; }    
};    

void mostrar(Libro l) {    
cout << l.titulo() << " tiene " << l.paginas() << " paginas" << endl;    
}    

int main() {    
 Libro l1("Fundamentos de C++", 474), l2("Por Fin: C ISO", 224), l3;    
 l3 = l1;    
 mostrar(l1), mostrar(l2), mostrar(l3);  
}

尽管没有定义复制构造函数并且编译器提供的默认复制构造函数在这种情况下无效,但执行是正确的,它在对 mostrar(l1)、mostrar( l2), mostrar(l3);.

但是,如果我们使用 mostrar(l1);莫拉尔(l2); mostrar(l3); 相反,我们会遇到预期的错误,最后一次调用不会正确显示最后一次调用,因为复制没有正确完成。 你知道 use 和 ; 之间有什么区别吗?为什么当你使用 , 时这段代码可以工作?

【问题讨论】:

  • 这绝对不是 c.
  • 俗话说,未定义的行为是未定义的。
  • 未定义的行为给你未定义的行为。你需要遵循三法则
  • 未定义的行为包括“似乎有效”作为一种可能的结果。
  • 抱歉所有的反​​对票。这是一个艰难的人群。您的问题很好,不幸的是,您偶然发现了由 2 个隐式行为引起的错误。 3/5 规则可以保护您免受此类影响,但显然这与您无关。我试图在我的回答中澄清这个问题。我还给你一个 +1 以抵消可笑的反对票数。

标签: c++ c++11


【解决方案1】:

您还没有编写复制构造函数或复制赋值运算符。 The Rule of 3 告诉我们,只要编写了析构函数,复制赋值运算符和复制构造函数也应如此。你也没有写,让我们看看会发生什么:

  1. l3 = l1 在这一行中,implicitly defined copy assignment operator 被调用,其定义如下:

Libro& Libro::operator=(const Libro& rhs) {
    this.tiulo_ = rhs.titulo_;
    this.paginas_ = rhs.paginas_;
}
  1. this.tiulo_ = rhs.titulo_ 这意味着l1l3 对象都指向由l1 的构造函数动态分配的“Fundamentos de C++”字符串
  2. l3.~Libro() 被隐式调用为 l3 leaves scope 将调用 delete [] titulo_ 破坏 l3 的“Fundamentos de C++”动态分配的成员 这也是 l1titulo_ 成员强>。
  3. l1.~Libro() 也被隐式调用,它将调用delete [] titulo_ 但是这次该成员被l3 删除,离开范围for a deleted pointer

将其传递给释放函数(双重删除)是未定义的行为

所以您的问题不是 ,; 的对比,而是由于不遵循 3 规则而导致的双重删除。


如果可以的话,与其建议您创建复制构造函数和复制赋值运算符,我建议您取消 Libro 并在 `pair 中使用 string,您的代码将像这样简单:

pair<string, int> l1 = make_pair("Fundamentos de C++"s, 474), l2 = make_pair("Por Fin: C ISO"s, 224), l3;

这当然需要你显式输出每个成员,例如:

cout << l1.first << " tiene " << l1.second << " paginas\n" << l2.first << " tiene " << l2.second << " paginas\n" << l3.first << " tiene " << l3.second << " paginas\n";

Live Example

【讨论】:

  • 但是即使你不遵守三规则,析构函数也不会被调用到“;”,所以当 l3 必须访问数据时,它们仍然存在。在 mostrar(l1), mostrar(l2), mostrar(l3) 执行时,没有调用析构函数,它们都在执行到达“;”时被调用。我真正的问题是为什么当你使用逗号时变量离开范围时编译器不调用析构函数。非常感谢。
  • @jram 我给你留下了评论here,关于这个问题的答案只不过是一种意见。如果你想要我没有受过教育的猜测,那就是开发环境在 main 结束时卸载了它的调试检查,然后在,-version 中调用析构函数。在;-版本中,Libro 对象的销毁可能被优化为在它们最后一次使用之后发生......在main 结束之前。请注意,这只是一种意见,因此不属于格式良好的答案。
猜你喜欢
  • 1970-01-01
  • 2021-12-25
  • 2020-05-10
  • 2014-09-20
  • 2010-10-28
  • 2015-10-04
  • 2012-08-12
  • 2011-02-18
  • 2019-12-21
相关资源
最近更新 更多