C++ 向量还存在吗? std::vector someOp(void) { 使用名称空间std; 矢量结果; //一些操作的结果 返回结果; } 内部主(空) { 使用名称空间std; 向量和结果=someOp(); }

C++ 向量还存在吗? std::vector someOp(void) { 使用名称空间std; 矢量结果; //一些操作的结果 返回结果; } 内部主(空) { 使用名称空间std; 向量和结果=someOp(); },c++,visual-c++,C++,Visual C++,someOp返回的向量是否存在于someOp()堆栈空间或main()堆栈空间中 我倾向于相信它不会被复制到主()堆栈空间,因为结果向量在两种方法中都有相同的地址。 这是不可编译的——在标准C++中,你不能绑定一个临时的( STD::vector < /COD> > >对于非const引用,也不,那不是有效的C++(并且没有被g++编译)。 似乎您正试图存储对返回的结果的引用,但这是不可能的,因为返回的结果存在于someOp的堆栈框架中,并且,尽管它仍将在someOp()返回之后存在,将在将来

someOp返回的向量是否存在于someOp()堆栈空间或main()堆栈空间中


我倾向于相信它不会被复制到主()堆栈空间,因为结果向量在两种方法中都有相同的地址。

这是不可编译的——在标准C++中,你不能绑定一个临时的(<代码> STD::vector < /COD> > <代码> >对于非const引用,

也不,那不是有效的C++(并且没有被g++编译)。
似乎您正试图存储对返回的
结果的引用,但这是不可能的,因为返回的
结果存在于
someOp
的堆栈框架中,并且,尽管它仍将在
someOp()返回之后存在,将在将来的某个时候被覆盖。

比这稍微复杂一点

是的,它最初位于
someOp
的堆栈空间中。但由于您是按值返回的,因此会生成一个副本。所以它还没有丢失

但是,当您将其存储到
vector&results
中时,会存储对它的引用。在语句结束后将变得无效。返回的向量是在语句结束后销毁的中间向量

因此,最终结果是
vector&results
成为一个悬空的“指针”

编辑:(见评论)


显然,代码根本不应该编译。但在VS2010中确实如此。因此,我的答案只适用于它确实编译的情况。

问题中的代码不正确,应该被拒绝,但问题仍然适用于它的轻微修改,但在讨论它之前,让我们描述以下更简单的程序:

std::vector<float> someOp(void)
{
    using namespace std;
    vector<float> results;
    // some operations done to results
    return results;
}

int main(void)
{
    using namespace std;
    vector<float> &results = someOp();
}
在上面的程序中,概念上有3个对象,在
f
内部有
x
,返回值未命名,最后是
m
内部
main
x
在[1]中创建,然后复制到[2]中返回的对象,该对象最终用于复制[3]中的construct
m

现在回到参考案例:

type f() {
   type x;        // [1]
   return x;      // [2]
}
int main() {
   type m = f();  // [3]
   m.const_function();
}
从概念上讲,同样的事情正在发生。在[1]中创建对象
x
,并将其复制到[2]中的返回值,现在在[3]中,返回值不用于初始化
r
,而是用于初始化编译器注入的未命名对象。最后,在[3]中,常量引用被绑定到未命名的对象。此时,未命名对象位于
main
的上下文中

至于当前编译器中实际发生的情况,调用约定决定了函数接口的实现方式。返回不适合寄存器的对象的函数的调用约定(在我所知道的所有编译器中)是通过向函数传递一个额外的隐藏指针来实现的。也就是说,调用者(
main,在本例中为
)在堆栈中保留空间,然后将指向该位置的指针传递给被调用者。这是调用者和被调用者同意返回的对象将生存的位置。这意味着调用方可以为原始示例中的
m
或第二种情况下的未命名对象保留空间,并传入指针。这将从等式中删除一个对象,即
m
(或未命名对象),返回的对象相同。下一步由编译器在处理被调用方时执行,如果它可以确定
x
将在所有代码路径中返回,它将不会在自己的堆栈中创建
x
,而是直接在隐藏指针引用的内存中创建。完成此操作后,净效果是程序中将有一个对象:

main
将获取内存,并传递一个指向
f
的指针,
f
将在该内存位置(位于
main
的堆栈空间)上创建
x
,并返回到
main
,在
const
引用的情况下,编译器将根据引用的名称别名未命名对象


(注意:引用和未命名对象不同,它们的类型实际上可能不同,但引用将是未命名对象的别名,为其提供名称)

按值返回不一定意味着副本。@Seth Carnegie:也不好。返回对局部变量的引用。@Duracell:您能澄清一下那个注释吗?@Duracell我指的是
const&
,这样就不坏了。@Seth:按const引用返回自动变量仍然是未定义的行为。您可以做的是将一个自动常量引用绑定到一个prvalue,比如
conststring&s=f()在Herb的示例中。请注意,
f
按值返回,而不是按常量引用返回!嗯,有意思。。。Visual C++又误导了我:(@ HeloRLDLD922:有时这样做:)嗯…所以我想问题是为什么VisualStudio2010让我编译它?是标准对此不清楚,还是微软又搞砸了?@helloworld922:VC++有语言扩展——你可以用/Za标志关闭它们,但是微软自己的头文件通常无法编译……想想吧。老实说,我不知道@神秘主义者下面的讨论可能会有更大的帮助。我会测试,但我认为我的笔记本电脑上没有包含Visual Studio的虚拟机。作为跟进,这在vc++中是“安全”代码吗?或者只是编译器允许您编译它?我现在假设VC++会尝试将
结果
绑定到与
someOp
相同的主结果。乐观主义者很可能内联
someOp
,或者做了一些其他的诡计,或者只是生成了不正确的代码。作为
type f() {
   type x;                // [1]
   return x;              // [2]
}
int main() {
   type const & r = f();  // [3]
   r.const_function();
}