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 都安全吗?如果没有,为什么?
一种情况下,它不安全,但不是因为内存的分配位置,而是因为"hi"
是const char*
类型(可能在 .text 或 .data 上谁知道(,并且 MyString
的构造器将其分配给 char*
类型的变量。如果有人试图通过str
修改字符串,就会发生未定义的行为。
第二种情况的问题在于,您的对象obj2
指向一个它没有所有权的字符串,无论它是堆栈还是堆。这不是一件可怕的事情,我已经看到了它的合法用途,但必须小心翼翼地完成。这个特定示例可以正常工作,因为对象和字符串都存在于堆栈中,并且因为它非常简单。
第一种情况是可以的,因为"hi"是一个静态字符串 - 一个全局常量。它的生存时间至少与 obj1 一样长(即使 obj1 是全局的或在堆上分配的(。
第二种情况可能不行,因为"hi 被复制到堆栈上的 str[] 中。
在这种特殊情况下,obj2 在 str 之前被销毁,所以没问题。如果您要返回 obj2 的副本,或者它本身被分配到堆上,那么这将是一个问题,因为它的寿命可能超过 str。
str 的数据([ 'h', 'i', '\0']( 在堆栈上 - 与局部变量相同。此内存仅在其保持在范围内时才有效 - 在这种情况下,直到 main(( 返回。由于 obj2 也在堆栈上,因此它本质上具有与 str 相同的生命周期,因此在这种情况下没有问题。更一般地说,您可以创建具有不同生存期的此对象的实例,例如"MyString *s = new MyString(str(;返回 s;"。现在,MyString 对象将比 str 活得更久,并且将继续指向 str 曾经导致未定义行为的内存。这是通常难以找到错误的常见来源。