和之间的区别;;?
编辑:我似乎没有很好地解释自己。我的问题不是关于3规则的问题,也不是关于如何以良好的方式实施它的问题。我的问题是为什么使用逗号时,在完成序列后调用析构函数而不是在变量离开范围时,我的意思是,仅当逗号之间的所有函数都完成时,对象才会被销毁,您可以
EDIT Looks like I didn't explain myself in a good way. My question was not about the Rule of 3, or how to implement it in a good way. My question is why when using comma the destructors are called after complete the sequence and not when the variables leave the scope, I mean, the objets are only destroyed when all the functions between comma have finished, you can see it adding a cout to the destructors.
在此示例中,
#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); 的调用中显示正确的信息。
Despite the copy constructor is not defined and the default copy constructor provide by the compiler is not valid in this case, the execution is correct and It shows the right information in the calls to mostrar(l1), mostrar(l2), mostrar(l3);.
但是,如果我们使用 mostrar(l1); mostrar(l2); mostrar(l3); 相反,我们会遇到预期的错误,因为复制未正确完成,所以最后一次呼叫不会正确显示最后一次呼叫。
您知道use和之间的区别是什么吗?为什么在使用时,此代码为何有效??
However, if we use mostrar(l1); mostrar(l2); mostrar(l3); instead, we would have the expected error, the last call wouldn't show correctly the last call, because the copy haven't been done properly. Do you know what is the diference between use , and ;? Why this code is working when you use ,?
您尚未编写副本构造函数或副本赋值运算符。 3规则告诉我们,只要析构函数具有在编写时,复制赋值运算符和复制构造函数也应如此。您也没有写过,所以让我们看看会发生什么:
You have not written a copy constructor or a copy assignment operator. The Rule of 3 tells us that anytime a destructor has been written, the copy assignment operator and copy constructor should be as well. You haven't written either so let's look at what happens:
-
l3 = l1
在此行中,调用隐式定义的副本分配运算符定义如下:
-
l3 = l1
in this line the implicitly defined copy assignment operator is called which will be defined like this:
Libro& Libro::operator=(const Libro& rhs) {
this.tiulo_ = rhs.titulo_;
this.paginas_ = rhs.paginas_;
}
-
this.tiulo_ = rhs.titulo _
这意味着l1
和l3
对象指向由l1
的构造函数动态分配的 Fundamentos de C ++字符串 -
l3 。〜Libro()
被隐式调用为l3
释放作用域,它将调用delete [] titulo _
销毁动态分配的 l3 ,它也是l1
的titulo _
成员。 -
l1。〜Libro()
也被隐式调用,这将调用delete [] titulo _
,但是这次成员被l3
删除,离开了范围用于删除的指针:
-
this.tiulo_ = rhs.titulo_
This means that both thel1
andl3
objects point to the "Fundamentos de C++" string that was dynamically allocated byl1
's constructor -
l3.~Libro()
is called implicitly asl3
leaves scope which will calldelete [] titulo_
destroying the "Fundamentos de C++" dynamically allocated member ofl3
which is alsol1
'stitulo_
member. -
l1.~Libro()
is called implicitly as well, which will calldelete [] titulo_
however this time that member was deleted byl3
leaving scope, for a deleted pointer:
将其传递给释放函数(双删除)是未定义的行为
Passing it to a deallocation function (double-delete) is undefined behavior
因此,您的问题不是,
和;
由于未遵循3规则而导致的重复删除。
So your issue is not the ,
versus the ;
but the double-delete that results from not following The Rule of 3.
如果可以的话,而不是建议您创建复制构造函数和复制赋值运算符,建议您不要使用 Libro
并使用 string
在一对中,您的代码将像这样简单:
If I may though, rather than suggesting you create a copy constructor and copy assignment operator, I'd suggest you do away with Libro
and use string
in a `pair your code would be as simple as this:
pair<string, int> l1 = make_pair("Fundamentos de C++"s, 474), l2 = make_pair("Por Fin: C ISO"s, 224), l3;
当然,这需要您明确输出每个成员,例如:
This will of course require you to explicitly output each member, for example:
cout << l1.first << " tiene " << l1.second << " paginas\n" << l2.first << " tiene " << l2.second << " paginas\n" << l3.first << " tiene " << l3.second << " paginas\n";