简体   繁体   English

C ++在技术上如何在没有副本的情况下移动函数返回值?

[英]C++ how is it technically possible to move a function return value without a copy?

When a function returns a value, this is put on the stack (the function stack frames are deleted, but the return value remains there until the caller gets it). 当一个函数返回一个值时,它被放到栈上(删除函数栈帧,但是返回值一直保留在那里直到调用者得到它为止)。

If the return value is on the stack how can the move get that value without copying it in the variable memory location? 如果返回值在堆栈上,那么移动如何在不将其复制到变量存储位置的情况下获取该值?

For example in this code: 例如下面的代码:

A a = getA();

The storage (Heap, stack, registers, etc) used to store the temporary used to return values from a function is implementation defined. 实现定义了用于存储用于从函数返回值的临时存储的存储(堆,堆栈,寄存器等)。 You could see it as: 您可以将其视为:

+-----------------------------+-------------------------+-----------------------------------------+
| target (caller stack frame) | temporary (unspecified) | return statement (function stack frame) | 
+-----------------------------+-------------------------+-----------------------------------------+ 

The value is passed from the right to the left. 该值从右向左传递。 Also note that the standard specifies that any compiler could elide the temporary and the assigments/copies/moves and directly initialize the target. 还要注意,该标准指定任何编译器都可以忽略临时文件和分配/副本/动作,并直接初始化目标。

Writting a class such as: 编写一个类,例如:

class trace
{
public:
    trace()
    { 
        std::cout << "Init" << std::endl;
    }

    ~trace()
    { 
        std::cout << "Destroy" << std::endl;
    }

    trace( const trace& )
    { 
        std::cout << "Copy init" << std::endl;
    }

    trace( trace&& )
    { 
        std::cout << "Move init" << std::endl;
   }

    trace& operator=( const trace& )
    { 
        std::cout << "Copy assign" << std::endl;
    }

    trace& operator=( trace&& )
    { 
        std::cout << "Move assign" << std::endl;
    }
};

And trying it with different compiler optimizations enabled is very ilustrative. 在启用了不同的编译器优化的情况下进行尝试非常有启发性。

In many implementations of C++, a function returning a "complex" data type is passed a hidden parameter that is a pointer to the space where the returned instance is to reside. 在C ++的许多实现中,将向返回“复杂”数据类型的函数传递一个隐藏参数,该参数是指向要返回的实例所驻留的空间的指针。 Essentially, the compiler turns Foo r = fun(); 本质上,编译器将Foo r = fun(); into 进入

char alignas(Foo) r[sizeof Foo]; // Foo-sized buffer, unitialized!
fun(&r);

As you can see, Foo is allocated on the stack in the caller's frame. 如您所见, Foo被分配在调用者框架中的堆栈上。 Now, within the implementation of fun there could be a copy. 现在,在执行fun中可能会有一个副本。 The construction 那个工程

Foo fun() {
  Foo rv;
  ...
  return rv;
}

is generally implemented as 通常实现为

void fun(Foo * $ret) {
  Foo rv;
  ..
  new ($ret) Foo(rv); // copy construction
}

When the return value optimizations are applied, this gets changed to 当应用返回值优化时,将其更改为

void fun(Foo * $ret) {
  Foo & rv = *(new ($ret) Foo);
  ...
  return;
}

Now there's no copying involved. 现在不涉及复制。 That's a mile-high overview of how an implementation might do it. 这是实现可能如何实现的概述。

You're assuming that A is an aggregate or primitive. 您假设A是一个集合或原始值。 If this is true then yes move and copy semantics are equivalent. 如果为真,则“是”移动和复制语义是等效的。 If however A is a complex type like vector then it will contain pointers to resources. 但是,如果A是像vector这样的复杂类型,则它将包含指向资源的指针。 When moving the object the pointers are copied without copying the value they point to. 移动对象时,将复制指针而不复制其指向的值。

When you say "move", I assuming you're referring to C++11 move constructors and the std::move function. 当您说“ move”时,我假设您指的是C ++ 11 move构造函数std::move函数。

Moving an object doesn't actually move the entire object. 移动对象实际上并不会移动整个对象。 It constructs a new one using its move constructor, which is allowed to take ownership of resources held by the original object instead of copying them. 它使用其move构造函数构造一个新对象,该构造函数允许获取原始对象持有的资源的所有权,而不是复制它们。 For example, if you write: 例如,如果您编写:

std::vector<int> foo = function_that_returns_a_vector();

the compiler may implement this by calling foo 's move constructor and passing it the temporary vector returned by the function. 编译器可以通过调用foo的move构造函数并向其传递函数返回的临时向量来实现此目的。 The move constructor will take ownership of the temporary vector's internal pointer to its heap-allocated contents, leaving the temporary vector empty. move构造函数将使用临时向量的内部指针对其堆分配的内容的所有权,而使临时向量为空。 Prior to C++11 and move support, foo 's copy constructor would've been called, which would've allocated new space on the heap to copy the returned vector's contents even though that returned vector is about to be destroyed and won't need its own copy any longer. 在C ++ 11和移动支持之前,将调用foocopy构造函数,该函数将在堆上分配新的空间以复制返回的向量的内容,即使该返回的向量将要销毁并获得胜利也是如此。不再需要自己的副本。

Note that the compiler won't necessarily implement that line by constructing foo from a returned temporary at all, though. 请注意,尽管如此,编译器不一定会通过从返回的临时结构构造foo来实现该行。 Depending on the compiler's platform-specific calling convention, the address of the (uninitialized) foo variable may be passed into the function in such a way that the function's return value is constructed directly into foo , avoiding the need for a copy after the function returns. 根据编译器特定于平台的调用约定,(未初始化的) foo变量的地址可以通过以下方式传递到函数中:将函数的返回值直接构造为foo ,从而避免在函数返回后进行复制。 This is called copy elision . 这称为复制省略

The easiest is to modify your method like this: 最简单的方法是像这样修改您的方法:

void getA(A& out);

A a;
getA(a);

However, your compiler does it's best to avoid such superfluity: Copy Elision 但是,您的编译器确实最好避免这种多余的情况: Copy Elision

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以在 C++ 中将返回值移动语义与受保护的复制构造函数一起使用? - Is it possible to use return value move semantics with a protected copy constructor in C++? 如何在不使用 c++ 中的“return”的情况下使用返回值退出 function - How to exit a function with a return value without using "return" in c++ 在 c++ 中,有没有办法在不发生移动或复制的情况下将值传递给构造函数? - In c++, is there a way to pass a value to a constructor without a move or copy happening? 如何在不退出 function 并随后将其存储在 c++ 的情况下返回一个值 - how to return a value without exiting a function and storing it subsequently, in c++ 如何在C ++中创建一个可以返回静态或自动存储对象而无需复制的函数? - How to make a function that can return either a static or automatic storage objects without copy in C++? C ++:是否可以在不返回的情况下终止非无效函数? - C++: Is It Possible to End a Non-Void Function Without a Return? C ++通过复制/移动按值语义传递 - C++ passing by value semantics with copy/move 是否可以在异步场景中将 C++ 堆栈对象传递给不同的线程而无需复制(但移动) - Is it possible to pass c++ stack object to a different thread without copy (but move) in async scenario 如何在不使用C ++ / C的阻塞函数的情况下将值从线程返回到主函数 - How to return value from the thread back to main function without using blocking function in C++/C 是否可以使c ++中的回调函数返回值? - Is it possible to make a callback function in c++ return a value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM