为什么对象 "a" 中的字符串在多次调用后没有在以下代码中被销毁?
Why isn't the string in object "a" getting destroyed in the following code after being called more than once?
所以,我这里有这段代码,看起来像这样...
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std ;
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
~A()
{
cout << "Destruction" << endl ;
delete str ;
}
};
void showVal(A a )
{
cout << a.str << endl ;
}
int main()
{
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
}
产生以下输出:
Construction
Hello
Destruction
Hello
Destruction
Hello
Destruction
Destruction
Process returned 0 (0x0) execution time : 0.015 s
Press any key to continue.
我的问题是,对象 "a" 中 "str" 的值是否应该在首次使用 "showVal" 函数调用后被销毁?为什么在那之后它仍然打印 "Hello" ?任何答案将不胜感激。
showVal
不会破坏对象 a
。它有自己的 a
副本,它将被销毁。您看到析构函数是为内部 a
调用的,而不是您在 main()
.
中初始化的析构函数
无论如何,由于copy elision.
,内部a甚至可能不会被创建和销毁
如果您想进一步了解它,请尝试以下代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std ;
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
~A()
{
cout << "Destruction " << str << endl ;
delete[] str ; //Thanks for @Vlad from Moscow
}
};
int i=0;
void showVal(A a ){
std::string temp="inner a:" + std::to_string(i);
a.str=new char[temp.size()+1]; //let us forget about memory leaks
strcpy(a.str,temp.c_str()) ;
cout << a.str << endl ;
++i;
}
int main()
{
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
}
在这种情况下,showVal
正在创建自己的临时对象 a
,因此析构函数调用只是表明它超出了范围,但是如果您想查看构造函数调用,那么添加一个 copy constructor
它将显示调用
A(const A&){
cout<<"copy constructor called\n";
}
程序有未定义的行为。
class 的析构函数不正确
~A()
{
cout << "Destruction" << endl ;
delete str ;
^^^^^^^^^^^
}
您必须使用 delete []
运算符。
~A()
{
cout << "Destruction" << endl ;
delete []str ;
^^^^^^^^^^^
}
你还必须定义复制构造函数。否则,隐式定义的复制构造函数使用 member-wise 复制源对象。在这种情况下,两个或多个对象将具有指向同一动态分配内存的指针,这会导致多次尝试删除同一动态分配内存..
如果要定义class至少要用下面的方法包括复制构造函数。
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
A( const A & a )
{
str = new char[strlen(a.str)+1] ;
strcpy( str, a.str );
}
~A()
{
cout << "Destruction" << endl ;
delete []str ;
}
};
然后在这些语句中
showVal(a) ;
showVal(a) ;
showVal(a) ;
将创建 class 的临时对象,它们创建自己的数据成员副本 str
,分配单独的内存范围。所以这些对象的销毁不会影响原始对象本身。
此处对象 a
通过值传递给函数 showVal
。对象 a
不是临时无名对象,因此不会调用 move copy constructor
。但是,是的,隐式的 default copy constructor
会被调用。现在,由于您尚未定义 default copy constructor
,因此只能看到一个 "Construction"
。
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
如果你现在定义一个default copy constructor
A(const A &obj)
{
cout<< "Copy Construction" << endl ;
str = new char[strlen(obj.str) + 1];
strcpy(str, obj.str);
}
然后你会看到:
Construction //due to A a("Hello")
Copy Construction //due to 1st showVal(a)
Hello
Destruction //due to 1st showVal(a)
Copy Construction //due to 2nd showVal(a)
Hello
Destruction //due to 1st showVal(a)
Copy Construction //due to 3rd showVal(a)
Hello
Destruction //due to 3rd showVal(a)
Destruction //due to A a("Hello")
现在打印 "Hello" 的原因是 delete str;
会导致未定义的行为(我遇到运行时错误)。正确的做法是 delete [] str;
所以,我这里有这段代码,看起来像这样...
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std ;
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
~A()
{
cout << "Destruction" << endl ;
delete str ;
}
};
void showVal(A a )
{
cout << a.str << endl ;
}
int main()
{
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
}
产生以下输出:
Construction
Hello
Destruction
Hello
Destruction
Hello
Destruction
Destruction
Process returned 0 (0x0) execution time : 0.015 s
Press any key to continue.
我的问题是,对象 "a" 中 "str" 的值是否应该在首次使用 "showVal" 函数调用后被销毁?为什么在那之后它仍然打印 "Hello" ?任何答案将不胜感激。
showVal
不会破坏对象 a
。它有自己的 a
副本,它将被销毁。您看到析构函数是为内部 a
调用的,而不是您在 main()
.
无论如何,由于copy elision.
,内部a甚至可能不会被创建和销毁如果您想进一步了解它,请尝试以下代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std ;
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
~A()
{
cout << "Destruction " << str << endl ;
delete[] str ; //Thanks for @Vlad from Moscow
}
};
int i=0;
void showVal(A a ){
std::string temp="inner a:" + std::to_string(i);
a.str=new char[temp.size()+1]; //let us forget about memory leaks
strcpy(a.str,temp.c_str()) ;
cout << a.str << endl ;
++i;
}
int main()
{
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
}
在这种情况下,showVal
正在创建自己的临时对象 a
,因此析构函数调用只是表明它超出了范围,但是如果您想查看构造函数调用,那么添加一个 copy constructor
它将显示调用
A(const A&){
cout<<"copy constructor called\n";
}
程序有未定义的行为。
class 的析构函数不正确
~A()
{
cout << "Destruction" << endl ;
delete str ;
^^^^^^^^^^^
}
您必须使用 delete []
运算符。
~A()
{
cout << "Destruction" << endl ;
delete []str ;
^^^^^^^^^^^
}
你还必须定义复制构造函数。否则,隐式定义的复制构造函数使用 member-wise 复制源对象。在这种情况下,两个或多个对象将具有指向同一动态分配内存的指针,这会导致多次尝试删除同一动态分配内存..
如果要定义class至少要用下面的方法包括复制构造函数。
class A
{
public:
char *str ;
A(char *s)
{
cout<< "Construction" << endl ;
str = new char[strlen(s)+1] ;
strcpy(str,s) ;
}
A( const A & a )
{
str = new char[strlen(a.str)+1] ;
strcpy( str, a.str );
}
~A()
{
cout << "Destruction" << endl ;
delete []str ;
}
};
然后在这些语句中
showVal(a) ;
showVal(a) ;
showVal(a) ;
将创建 class 的临时对象,它们创建自己的数据成员副本 str
,分配单独的内存范围。所以这些对象的销毁不会影响原始对象本身。
此处对象 a
通过值传递给函数 showVal
。对象 a
不是临时无名对象,因此不会调用 move copy constructor
。但是,是的,隐式的 default copy constructor
会被调用。现在,由于您尚未定义 default copy constructor
,因此只能看到一个 "Construction"
。
A a("Hello") ;
showVal(a) ;
showVal(a) ;
showVal(a) ;
如果你现在定义一个default copy constructor
A(const A &obj)
{
cout<< "Copy Construction" << endl ;
str = new char[strlen(obj.str) + 1];
strcpy(str, obj.str);
}
然后你会看到:
Construction //due to A a("Hello")
Copy Construction //due to 1st showVal(a)
Hello
Destruction //due to 1st showVal(a)
Copy Construction //due to 2nd showVal(a)
Hello
Destruction //due to 1st showVal(a)
Copy Construction //due to 3rd showVal(a)
Hello
Destruction //due to 3rd showVal(a)
Destruction //due to A a("Hello")
现在打印 "Hello" 的原因是 delete str;
会导致未定义的行为(我遇到运行时错误)。正确的做法是 delete [] str;