class MyString
{
char* str;
public:
MyString(char* _str)
{
str = _str;
}
};
int main()
{
MyString obj1("hi"); // case 1
char str[] = "hi";
MyString obj2(str); // case 2
}
这里我没有在成员str的构造函数中从堆中分配内存。案例1和案例2都安全吗?如果没有,为什么?
答案 0 :(得分:4)
在第一种情况下,它不安全,但不是因为内存的分配位置,而是因为"hi"
的类型为const char*
(可能是.text或.data知道) ,MyString
的构造函数将其赋值给char*
类型的变量。如果有人试图通过str
修改字符串,则会发生未定义的行为。
第二种情况的问题是你的对象obj2
指向一个没有所有权的字符串,如果它是堆栈或堆则无关紧要。这不是一件可怕的事情,我已经看到了合法用途,但必须小心谨慎。这个特殊的例子可以正常工作,因为对象和字符串都存在于堆栈中,因为它非常简单。
答案 1 :(得分:3)
第一种情况是可以的,因为“hi”是一个静态字符串 - 一个全局常量。它将至少与obj1一样长(即使obj1是全局的或者在堆上分配)。
第二种情况可能不正常,因为“hi被复制到堆栈中的str []。
在这种特殊情况下,obj2在str之前被销毁,所以很好。如果你要返回一个obj2的副本,或者它本身是在堆上分配的,那么这将是一个问题,因为它可能比str更长。
str(['h','i','\ 0'])的数据在堆栈上 - 与局部变量相同。 该内存仅在保留在范围内时才有效 - 在这种情况下,直到main()返回。 由于obj2也在堆栈上,它基本上与str具有相同的生命周期,因此在这个实例中没有问题。 但更一般地说,您可以使用不同的生命周期创建此对象的实例,可能类似于“MyString * s = new MyString(str); return s;”。现在,MyString对象将比str更长,并且将继续指向str曾经导致未定义行为的内存。 这是常常难以找到的错误的常见来源。