如果我有以下代码:
{
UnicodeString sFish = L"FISH";
char *szFish = AnsiString(sFish).c_str();
CallFunc(szFish);
}
那么临时AnsiString
创建的范围是什么,szFish
指向有效数据的时间是多久?它仍然对该CallFunc
功能有效吗?
它的范围会只持续一行,还是持续整个块?
如果我有以下代码:
{
UnicodeString sFish = L"FISH";
char *szFish = AnsiString(sFish).c_str();
CallFunc(szFish);
}
那么临时AnsiString
创建的范围是什么,szFish
指向有效数据的时间是多久?它仍然对该CallFunc
功能有效吗?
它的范围会只持续一行,还是持续整个块?
szFish
在调用 之前是无效的CallFunc()
,因为AnsiString
它是一个临时对象,它立即被破坏并szFish
指向其刚刚被删除的内部缓冲区。
确保该AnsiString
实例对 的调用有效CallFunc()
。例如:
CallFunc(AnsiString(sFish).c_str());
我会替换:
char *szFish = AnsiString(sFish).c_str();
和:
AnsiString as(sFish);
char *szFish = as.c_str();
我不知道这个AnsiString
类,但在你的代码中,它的析构函数会在你调用之前触发CallFunc()
,并且很可能会释放你指向的字符串*szFish
。当您用堆栈上的“命名”对象替换临时对象时,它的生命周期将延长到定义它的块的末尾。
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
能够读取原始字符串。
在这种情况下, 的范围AnsiString
是“从调用到 之前c_str()
,直到之后”。
这样想可能会有所帮助:
char *szFish;
{
AnsiString tmpString(sFish);
szFish = tmpString.c_str();
}