返回语句复制值

我对此感到疑惑是因为范围问题

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
}

所以我的问题是 return 语句会一直复制吗?在这种情况下,它似乎工作,所以我相信,返回确实复制。如果它确实复制了,它会在每种情况下都复制吗?

55289 次浏览

在您的情况下,它将返回一个副本

如果你的代码是

subline_t& subline(int, int)

然后它将返回一个引用,这将导致未定义的行为。

是的,在这种情况下会有一个副本。如果你像这样修改函数声明:

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

那就不会复制了。但是,在您的特定情况下,返回对堆栈上分配的对象的引用是无效的。问题是,在调用方有机会使用对象之前,该对象将被销毁并失效。

这与 C + + 常用的 返回值优化有关,在您所描述的情况下,这种 返回值优化可以避免执行实际的复制操作。最终的结果(或者应该)与复制完成后的结果相同,但是您应该注意到这种优化。在某些情况下,这种优化的存在可以改变程序的可观察行为。

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

是的,对于一个声明返回 struct的函数,这样一个结构的 return将会复制它(尽管编译器被授权优化副本,基本上在它可以证明优化在语义上是无害的情况下,你可以推理“好像”复制是有保证的)。

但是,既然 是的标记为 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
}

它总是会返回一个副本。

如果希望避免在返回时复制对象的性能影响,可以声明一个指针,使用 new 构建对象的实例,并返回指针。在这种情况下,将复制指针,但不复制对象。

仅供参考,因为在本例中您只使用了一个 struct (ure) ,所以它的行为与 C 语言相同。

虽然这是一个语言特性,但它是 建议不得使用

通过值而非引用返回 C + + 中的对象。

对 subline _ t t 的引用超出了作用域

不,对象已被复制。

Return 语句是否总是复制

是的,但不是... 从语义上来说,它表现得像是拷贝,但是有一种叫做返回值优化的东西可以节省复制建构子。

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

它返回一个副本,这就是您希望它做的。更改它以返回引用将导致赋值到 line 中的未定义行为。

然而,在 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.
}

返回的类或结构可以复制,也可以不复制,这取决于编译器是否使用了复制省略。参见“什么是拷贝省略和返回值优化”的答案。什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什么是拷贝省略和返回值优化? 什? 简而言之,它是否被复制取决于很多因素。

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

最后,如果不能信任副本省略,并且希望避免副本,则可以使用并返回 unique_ptr而不是引用。对象本身不会被复制,尽管 unique_ptr本身可能会也可能不会(同样,取决于复制省略!).然而,如果由于某种原因没有发生 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将无法编译。

我不同意和不建议将向量返回到更改值: 作为参考是否更快通过:

void vectorial(vector <double> a, vector <double> b, vector <double> &c)
{
c[0] = a[1] * b[2] - b[1] * a[2]; c[1] = -a[0] * b[2] + b[0] * a[2]; c[2] = a[0] * b[1] - b[0] * a[1];
}
//This is slow!!!:
vector <double> vectorial(vector <double> a, vector <double> b)
{
vector <double> c{ a[1] * b[2] - b[1] * a[2], -a[0] * b[2] + b[0] * a[2], a[0] * b[1] - b[0] * a[1] };
return c;
}

我在 VS2015上进行了测试,发布模式下的结果如下:

参考文献: 8.01 MOP 和返回矢量: 5.09 MOP 差60% !

在调试模式下,情况要糟糕得多:

参考文献: 0.053 MOP,返回矢量: 0.034 MOP