这个字符串的范围是什么?

时间:2012-11-20 13:39:52

标签: c++ c++builder c++builder-xe

如果我有以下代码:

{
    UnicodeString sFish = L"FISH";
    char *szFish = AnsiString(sFish).c_str();

    CallFunc(szFish);
}

那么创建的临时AnsiString的范围是什么,以及szFish指向有效数据的时间有多长?它仍然对CallFunc函数有效吗?

它的范围只是一行,还是整个块?

4 个答案:

答案 0 :(得分:5)

在调用szFish之前,

CallFunc()无效,因为AnsiString是一个立即被破坏的临时对象,szFish指向其内部缓冲区已被删除。

确保AnsiString实例对CallFunc()的调用有效。例如:

CallFunc(AnsiString(sFish).c_str());

答案 1 :(得分:4)

我会替换:

char *szFish = AnsiString(sFish).c_str();

使用:

AnsiString as(sFish);
char *szFish = as.c_str();

我不知道AnsiString类,但在您的代码中,析构函数会在您调用CallFunc()之前触发,并且很可能会释放您使用*szFish指向的字符串。当您使用堆栈上的“命名”对象替换临时对象时,其生命周期将延长到定义它的块的末尾。

答案 2 :(得分:2)

C ++ 11标准$ 12.2.3说:

  

当实现引入类的临时对象时   有一个非平凡的构造函数(12.1,12.8),它应该确保a   为临时对象调用构造函数。同样,   析构函数应该被称为临时的非平凡的   析构函数(12.4)。 临时对象作为最后一步被销毁   评估(词法上)包含的全表达式(1.9)   创建它们的地方。即使进行评估也是如此   以抛出异常结束。价值计算和副作用   销毁临时对象只与   完整表达,而不是任何特定的子表达式。

(强调我的)

还有其他注意事项,但在这种情况下它们并不适用。在您的情况下,完整表达式是本声明的指示部分:

char *szFish = AnsiString(sFish).c_str();
//             ^^^^^^^^^^^^^^^^^^^^^^^^^

因此,分配了即时szFish,将调用临时对象的析构函数(即AnsiString(sFish)),并释放其内部内存表示(c_str()指向的位置) 。因此,szFish将立即成为悬空指针,任何访问都将失败。

你可以说

来解决这个问题
CallFunc(AnsiString(sFish).c_str());

相反,在这里,临时将在完整表达式之后(再次)在;)之后被销毁({1}}并且CallFunc将能够读取原始字符串。

答案 3 :(得分:1)

在这种情况下,AnsiString的范围是“从调用c_str()之前,直到紧接着。”以这种方式思考可能会有所帮助:

char *szFish; 

{ 
    AnsiString tmpString(sFish); 
    szFish = tmpString.c_str(); 
}