【问题标题】:passing( = returning) by reference a vector at the exit of function在函数的出口通过引用一个向量传递(=返回)
【发布时间】:2014-05-13 00:08:33
【问题描述】:

这个 c++ 片段合法吗?

vector<myType>& aClass::aFunction()
{
    vector<myType> aVec;

    //do stuff

    return aVec;
}

然后在另一个函数中使用它:

vector<myType> getVec = aFunction();

所以基本上,我在问:如果我声明 getVec 并获得对 aVec 向量数据的引用,那么数据会在 aFunction() 死亡后继续存在吗?

【问题讨论】:

  • 如果你要求'合法',是的,它可以很好地编译。

标签: c++ function return-value pass-by-reference


【解决方案1】:

不,这很顽皮。您不能返回对局部变量的引用。

只需按值传回即可。编译器应该为你做返回值优化,所以你不应该得到浪费的副本。

vector<myType> aClass::aFunction()
{
    vector<myType> aVec;
    // ...
    return aVec;
}

【讨论】:

  • 技术上你可以。否则这将是一个错误,而不是警告。该代码是合法的,但我想知道什么用例不会导致 UB。
  • @luk32 我的回答是对“合法吗?”这个问题的回答。它不是由语言定义的。在您的回答中,您说特定警告是“几乎总是”错误:您能否提供一个示例,说明返回对局部变量的引用实际上是有效的?
  • 非法代码是否编译?就是那个问题。我已经告诉过你,我不知道不会导致 UB 的情况,但它确实可以编译。为什么总是会编译非法代码?也许它本身值得一个问题。不知道。
  • @luk32 您将编译器认为有效的内容与 C++ 标准定义的有效内容混淆了。
  • 不,我没有混淆任何东西,我是在问。那些不是修辞问题=)。所以基本上,具有明确行为的代码(可能是序列点的状态)仅从标准的角度来看才有效?那正确吗?我很想知道这是否是一个有效的问题。我什至不确定“有效代码”一词是否在 TBH 的任何地方定义。
【解决方案2】:

不,即使编译器让它溜走,变量也会随着函数的范围而死,所以你会有一个悬空引用并有效地进入未定义行为状态。

按值返回,任何下降编译器都会执行(N)RVO。有一些限制,因此您应该始终检查编译器的要求。特别是如果有多个出口点。但这是最好的做法,可以生成最干净、最快的代码。

附录:

它确实会在clang++g++ 上生成(“只是”)警告:

luk32@debianvm:~/projects/tests$ g++ ./dangling_reference.cpp 
./dangling_reference.cpp: In function 'std::vector<int>& test()':
./dangling_reference.cpp:6:17: warning: reference to local variable 'v' returned [-Wreturn-local-addr]
     vector<int> v(10);
                 ^
luk32@debianvm:~/projects/tests$ clang++ ./dangling_reference.cpp 
./dangling_reference.cpp:7:12: warning: reference to stack memory associated with local variable 'v' returned [-Wreturn-stack-address]
    return v;

但是我建议将这些警告标记为错误,因为它们几乎总是如此(几乎我的意思是为了安全起见,我不知道如何返回对局部变量的引用而不进入 UB),并考虑在编译器命令中添加适当的开关。例如:

g++ -Werror=return-local-addr ./dangling_reference.cpp
clang++ -Werror=return-stack-address ./dangling_reference.cpp

IMO,如果您的项目足够大,除了手动编译之外,这是一个很好的做法。

【讨论】:

    【解决方案3】:

    否 - 当函数返回时,自动对象被销毁,使引用无效。对引用进行任何操作都会产生未定义的行为。

    你的编译器应该警告你;如果没有,请调高警告级别。

    改为按值返回向量。如果您担心复制它的成本,移动语义和/或省略会解决这个问题。

    【讨论】:

      猜你喜欢
      • 2013-07-07
      • 2012-07-17
      • 2015-05-24
      • 2018-07-27
      • 2019-06-13
      • 1970-01-01
      • 2011-03-14
      • 2017-03-10
      • 1970-01-01
      相关资源
      最近更新 更多