我正在从java转向c ++,我试图理解构造/破坏对象.在java时,我这样做
Myclass c=createANewObject();
c=createANewObject();
Run Code Online (Sandbox Code Playgroud)
旧的c是垃圾收集的,另一个是用同一个名称创建的.
如果我尝试在c ++中做同样的事情我会得到奇怪的行为.
class my_class
{
string content;
time_t t;
public:
my_class(string c);
~my_class();
};
my_class::my_class (string c)
{
content=c;
cout<<"Init -" << content << "-" << t <<endl;
}
my_class::~my_class()
{
cout<<"Destroyed -" << content << "-" << t <<endl;
}
my_class get_new_object(string s)
{
my_class c(s);
return c;
}
int main()
{
my_class c=get_new_object("A");
c=get_new_object("B");
}
Run Code Online (Sandbox Code Playgroud)
而不是得到
Init -A-
Init -B-
destr.A
destr.B
Run Code Online (Sandbox Code Playgroud)
因为首先我创建A,然后创建B,然后A被销毁,并且范围结束,因此B被销毁
我明白了
Init -A-1456178128 Init -B-1456178131 Destr.B-1456178131 Destr.B-1456178131
所以我的A被创造而不被摧毁,而B ......被摧毁了两次?
在Java中,您的代码执行以下顺序:
c以引用该对象c从旧对象释放引用并使其引用新对象在C++中,您的代码是完全不同的.不要被类似的语法所迷惑.在C++中,您可以执行与Java代码几乎相同的步骤; 通过使用不同的语法.但您实际使用的语法执行以下操作:
get_new_object::c("A")get_new_object::cmain::c通过复制返回的副本来初始化对象get_new_object::c("B")get_new_object::cmain::c通过从返回的对象复制细节进行更新main::c可以通过称为复制省略的过程来优化上述一些副本.如果你使用编译器开关来禁用复制省略,你应该看到所有上述步骤,即5个析构函数,2个普通构造函数,以及(如果你还为其他特殊函数添加输出),3个复制构造函数和1个赋值运算符.
NB.在C++ 11中,临时对象可以移入和移出(如果编译器决定不使用elision)而不是复制.但是我把它留下来以保持清单简单.
这在某种程度上是特定于编译器和版本 ( C++11) 的。
get_new_object创建一个条目,并按值返回它。这可能会创建 3 个对象、2 个对象或 1 个对象。
编译器创建一个堆栈对象。这会将复制构造函数放入临时构造函数中。该临时文件使用另一个复制构造函数移至 C 中
更智能的编译器会丢失中间的临时值。
一个非常聪明的编译器意识到只有一个结果很重要。c++11通过移动构造函数提供帮助。
将创建复制/移动构造函数,但不会在代码中报告。
析构函数准确地描述了创建的对象数量 (2)
编译器认为它只需要 A。因此
init A
Run Code Online (Sandbox Code Playgroud)
当b被创建时,就创建了一个新对象。这是构造成的副本c
Init b
Run Code Online (Sandbox Code Playgroud)
然后 b temp 被破坏。
Destr b
Run Code Online (Sandbox Code Playgroud)
然后就c被毁了
destr b
Run Code Online (Sandbox Code Playgroud)