是否返回语句复制值

我想知道这是因为范围问题。 例如,考虑代码

typedef struct { int x1;/*top*/ int x2;/*bottom*/ int id; } subline_t; subline_t subline(int x1, int x2, int id) { subline_t t = { x1, x2, id }; return t; } int main(){ subline_t line = subline(0,0,0); //is line garbage or isn't it? the reference //to subline_t t goes out of scope, so the only way this wouldn't be garbage //is if return copies } 

所以我的问题是,返回语句是否总是复制? 在这种情况下,它似乎工作,所以我导致相信,返回是复制。 如果它复制,它会在任何情况下复制?

是的,在这种情况下,将会有一份复印件。 如果你像这样改变函数声明:

 subline_t &subline(int x1, int x2, int id) { 

那么不会做任何复制。 但是,在您的具体情况下,返回对堆栈中分配的对象的引用将无效。 问题是在调用者有机会使用它之前,对象将被破坏和失效。

这与C ++的常见返回值优化有关,可以避免在描述的情况下执行实际的复制操作。 最终的结果是(或者应该)和拷贝完成一样,但是你应该知道优化。 在某些情况下,这种优化的存在可以改变程序的可观察行为。

它会一直返回一个副本。

如果要避免在返回时复制对象的性能命中,则可以声明一个指针,使用new构build对象的一个​​实例,然后返回指针。 在这种情况下,指针将被复制,但对象不会。

在你的情况下,它会返回一个副本

如果你的代码是

 subline_t& subline(int, int) 

那么它会返回一个引用,这会导致未定义的行为。

是的,对于声明返回一个structreturn这样一个结构体将会复制它(尽pipe编译器有权优化拷贝,实质上在它certificate优化在语义上是无害的情况下,你可以推理“复制得到保证)。

然而,既然你把这个标记为C ++,而不是C,为什么不给你的struct提供一个构造函数,而是…? 看起来更清晰,更直接…! – )

是的,回报是副本

 subline_t subline(int x1, int x2, int id) { subline_t t = { x1, x2, id }; return t; } 

如果你把一个参考,那么它不是一个副本

 subline_t & subline(int x1, int x2, int id) { subline_t t = { x1, x2, id }; return t; // will result in corruption because returning a reference } 

它返回一个副本,这是你想要做的。 将其更改为返回引用将导致分配到行中的未定义行为。

然而,在C ++中这样做的习惯方式是使用构造函数和赋值列表。 这更好地封装了代码和数据结构,并且可以避免编译器可以自由构造/破坏/复制的大量中间对象。

 struct subline_t { int x1;/*top*/ int x2;/*bottom*/ int id; // constructor which initialises values with assignment list. subline_t(int the_x1, int the_x2, int the_id) : x1(the_x1), x2(the_x2), id(the_id) { } }; int main(){ subline_t line2(0,0,0); // never requires a copy or assignment. } 

对于你定义的结构subline_t ,是的,它总是会返回一个副本。

用C ++完成对象,而不是通过引用。

对subline_t t的引用超出了范围

不,对象被复制。

将返回语句总是复制

是的,而不是…在语义上,它的行为就像复制,但有一些被称为返回值优化,保存复制构造函数。

 foo make_foo() { foo f(1,2,3); return f; } foo ff=make_foo(); /// ff created as if it was created with ff(1,2,3) -- RVO foo ff2; ff2=make_foo(); /// instance of foo created and then copied to ff2 and then old /// instance destroyed 

根据编译器是否使用copy elision,可以或不可以复制返回的类或结构。 请参阅什么是复制elision和返回值优化的答案? 总之,是否复制取决于许多事情。

你当然可以通过返回一个引用来避免副本。 在你的例子中,返回一个引用是无效的(尽pipe编译器会允许),因为本地结构被分配在栈上,因此返回的引用指的是一个释放的对象。 但是,如果对象被传递给你的函数(直接或作为对象的成员),你可以安全地返回一个引用,避免copy-on-return。

最后,如果你不能信任copy elision并且你想避免拷贝,你可以使用并返回一个unique_ptr而不是一个引用。 该对象本身不会被复制,虽然unique_ptr本身可能会或可能不会(再次,取决于复制elision!)。 但是,如果unique_ptr复制删除不是由于某种原因而发生的,复制/移动unique_ptr非常便宜。

这是一个使用unique_ptr的例子:

 #include <memory> struct A { public: int x; int y; A(int x, int y) : x(x), y(y) { } }; std::unique_ptr<A> returnsA() { return std::make_unique<A>(3, 4); } int main() { auto a = returnsA(); } 

注意你必须(不幸地)为你的结构声明一个构造函数,否则由于C ++的不足, make_unique将不能编译。

只是供参考,因为在这种情况下,你只使用一个结构(ure),这是在C语言相同的行为。

虽然这是一种语言function,但build议不要使用它