我从java转到c ++,我尝试理解构造/破坏对象。 在我做的时候
Myclass c=createANewObject();
c=createANewObject();
旧的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");
}
而不是
Init -A-
Init -B-
destr.A
destr.B
因为首先创建A,然后创建B,然后A被销毁,范围结束,因此B被销毁
我得到了
Init -A-1456178128 Init -B-1456178131 Destr.B-1456178131 Destr.B-1456178131
所以我的A被创造而不被摧毁,B ......被摧毁了两次?
答案 0 :(得分:8)
在Java中,您的代码按以下顺序执行:
c
以引用该对象c
并使其引用新对象在C ++中,您的代码完全不同。不要被类似的语法所迷惑。在C ++中,可以执行与Java代码几乎相同的步骤;通过使用不同的语法。但您实际使用的语法如下:
get_new_object::c("A")
get_new_object::c
main::c
初始化
get_new_object::c("B")
get_new_object::c
main::c
main::c
上述某些副本可能会被称为 copy elision 的过程优化。如果你使用编译器开关来禁用复制省略,你应该看到所有上述步骤,即5个析构函数,2个普通构造函数,以及(如果你还为其他特殊函数添加输出),3个复制构造函数和1个赋值运算符。
NB。在C ++ 11中,临时对象可以移入和移出(如果编译器决定不使用elision)而不是复制。但是我把它留下来以保持清单简单。
答案 1 :(得分:1)
这在某种程度上是编译器和版本(C++11
)。
get_new_object
创建一个条目,并按值返回。这可能会创建3个对象,2个对象或1个。
编译器创建堆栈对象。 这会将复制构造函数转换为临时构造函数。 此临时使用另一个复制构造函数移动到C
更聪明的编译器丢失了中间临时。
一个非常聪明的编译器意识到只有一个结果很重要。 c++11
通过移动构造函数来帮助。
将创建复制/移动构造函数,但不会在代码中进行报告。
析构函数准确描述了创建的对象数量(2)
编译器认为它只需要A. 因此
init A
创建b时,会创建一个新对象。这是复制到c
Init b
然后b temp被破坏。
Destr b
然后c
被销毁
destr b
答案 2 :(得分:1)
<link href="favicon.ico" rel="icon" type="image/x-icon"/>