2

如果我有以下代码:

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

    CallFunc(szFish);
}

那么临时AnsiString创建的范围是什么,szFish指向有效数据的时间是多久?它仍然对该CallFunc功能有效吗?

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

4

4 回答 4

5

szFish在调用 之前是无效的CallFunc(),因为AnsiString它是一个临时对象,它立即被破坏并szFish指向其刚刚被删除的内部缓冲区。

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

CallFunc(AnsiString(sFish).c_str());
于 2012-11-20T13:42:52.833 回答
4

我会替换:

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

和:

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

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

于 2012-11-20T13:43:08.270 回答
2

C++11 标准 $12.2.3 说:

当实现引入具有非平凡构造函数(12.1、12.8)的类的临时对象时,它应确保为临时对象调用构造函数。类似地,应该使用非平凡的析构函数(12.4)调用析构函数。临时对象被销毁作为评估完整表达式(1.9)的最后一步,该完整表达式(在词法上)包含它们被创建的点。即使评估以抛出异常结束也是如此。销毁临时对象的值计算和副作用仅与完整表达式相关联,与任何特定子表达式无关。

(强调我的)

对此还有其他警告,但它们不适用于这种情况。在您的情况下,完整的表达式是此语句的指示部分:

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

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

你可以通过说

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

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

于 2012-11-20T13:55:10.653 回答
1

在这种情况下, 的范围AnsiString是“从调用到 之前c_str(),直到之后”。

这样想可能会有所帮助:

char *szFish; 

{ 
    AnsiString tmpString(sFish); 
    szFish = tmpString.c_str(); 
}
于 2012-11-20T13:47:16.873 回答