【问题标题】:What happens when a function returns a CString?当函数返回 CString 时会发生什么?
【发布时间】:2017-02-23 18:19:20
【问题描述】:

我对内存和指针有非常透彻的了解,但我需要稍微复习一下 C++ 如何在幕后管理一些对象。

考虑以下代码:

void Test()
{
    LPCTSTR psz = (LPCTSTR)GetString();
}

CString GetString()
{
    return CString(_T("abc"));
}

问题:

  1. 有人能具体说明GetString() 如何返回一个本地对象并且它在调用者中仍然有效吗?

  2. 由于GetString()的结果没有存储在任何地方,如何删除?

  3. psz 是否可以保证“安全”地用于整个 Test() 函数?

很抱歉在这个例子中使用了旧的类,但这就是我现在正在使用的。

【问题讨论】:

  • LPCTSTR psz = (LPCTSTR)GetString(); 这种演员阵容完全错误,混淆了实际发生的一切。这是未定义的行为,仅此而已。
  • @πάνταῥεῖ:但它编译和运行都很好。所以我正在寻找原因的解释。
  • @πάντα 假设这是 MFC CString 类,我相信有一个用户定义的转换为 LPCSTR。
  • “但它编译得很好。” 就像reinterpret_cast 一样。您确定要申请reinterpret_cast
  • (1) GetString 返回一个本地对象的副本(虽然实际的复制可能会被省略,而本地临时对象直接返回)。 (2) GetString() 的结果是临时的。像大多数临时变量一样,它会在完整表达式的末尾自动销毁(本质上是在分号处)。 (3) psz 获取指向由该临时管理的缓冲区的指针。一旦临时对象被销毁,psz 就会变得悬空。任何实际使用它的尝试都会表现出未定义的行为。

标签: c++ visual-c++ mfc object-lifetime


【解决方案1】:
  1. GetString 返回一个本地对象的副本(虽然实际的复制可能会被省略,直接返回本地临时对象)。

  2. GetString() 的返回值是临时的。与大多数临时变量一样,它会在完整表达式的末尾(本质上是在分号处)自动销毁。

  3. psz 获取指向由该临时管理的缓冲区的指针。一旦临时对象被销毁,psz 就会变得悬空。任何实际使用它的尝试都会表现出未定义的行为。

【讨论】:

  • 谢谢。所以听起来我应该将结果分配给CString,如果我想继续使用它。但你的第二个答案表明我可能对DoSomething((LPCTSTR)GetString()); 之类的表达没意见。
  • 是的,没关系,只要DoSomething() 不试图挂在函数调用之外的指针上。
  • 2 点值得注意:在这种情况下,进行显式函数调用 CString::GetString() 通常是一个更好的主意,而不是强制转换运算符。我相信您还可以将临时对象绑定到对 const 的引用,从而将临时对象的生命周期延长到引用的生命周期,即 const CString& s = GetString(); 使 s 在整个 void Test() 中有效。
  • @JonathanWood:如果没有别的,那就是thwarts off the know-it-alls。更严重的是,用户定义的强制转换运算符很危险,因为您无法仅通过查看表达式 (LPCTSTR)GetString() 来判断发生了什么。函数调用是显式的,并且可以在调用点立即识别。没有引入歧义,无需猜测。
  • @JonathanWood:可读性和可维护性。如果你决定用另一个字符串类替换CString,C 风格的转换可能会变成一个怪物,它唯一的工作就是隐藏编译器错误。
猜你喜欢
  • 1970-01-01
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 2020-04-19
  • 2015-08-06
相关资源
最近更新 更多