programing tip

문 복사 값을 반환합니까?

itbloger 2020. 11. 22. 19:08
반응형

문 복사 값을 반환합니까?


범위 문제 때문에 이것에 대해 궁금합니다. 예를 들어, 코드를 고려하십시오.

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 문이 항상 복사됩니까? 이 경우 작동하는 것처럼 보이므로 반환이 복사를한다고 믿게됩니다. 복사하면 모든 경우에 복사됩니까?


예,이 경우 사본이 만들어집니다. 다음과 같이 함수 선언을 변경하면 :

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

그러면 복사본이 만들어지지 않습니다. 그러나 특정 경우 스택에 할당 된 개체에 대한 참조를 반환하는 것은 유효하지 않습니다. 문제는 호출자가 사용하기 전에 객체가 파괴되고 무효화된다는 것입니다.

이는 설명한 경우 실제 복사 작업을 피할 수 있는 일반적인 C ++ 용 반환 값 최적화 와 관련이 있습니다. 최종 결과는 복사가 완료된 것과 동일하거나 동일해야하지만 최적화에 대해 알고 있어야합니다. 이 최적화의 존재는 경우에 따라 프로그램의 관찰 가능한 동작을 변경할 수 있습니다.


귀하의 경우에는 사본을 반환합니다.

코드가

subline_t& subline(int, int)

그런 다음 참조를 반환하고 정의되지 않은 동작을 생성합니다.


함수가를 반환하는 선언에 대한 예 struct, return이러한 구조체가 복사됩니다의 컴파일러는 권한을 부여하고 있지만 (당신이 이유 수, 그것은 최적화 의미 무해 입증 할 수있는 곳은 경우에 기본적으로, 멀리 복사 최적화 "만약 그대로" 복사가 보장됨).

그러나 이후 이 C로 태그 ++, C, 왜 당신을 제공하지하지 struct않고, 생성자와 함께 ...? 더 명확하고 직접적으로 보입니다 ...!-)


항상 복사본을 반환합니다.

반환시 개체를 복사하는 성능 저하를 피하려면 포인터를 선언하고 new를 사용하여 개체의 인스턴스를 빌드 한 다음 포인터를 반환 할 수 있습니다. 이 경우 포인터는 복사되지만 개체는 복사되지 않습니다.


예, 반품은 사본입니다.

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 ++에서 개체를 복원합니다.

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

원하는 작업 인 복사본을 반환합니다. 참조를 반환하도록 변경하면 줄 할당에서 정의되지 않은 동작이 발생합니다.

그러나 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정의한 구조의 경우 예, 항상 복사본을 반환합니다.


반환 된 클래스 또는 구조체는 컴파일러가 복사 제거를 사용하는지 여부에 따라 복사되거나 복사되지 않을 수 있습니다. 복사 제거 및 반환 값 최적화 란 무엇입니까?에 대한 답변을 참조하십시오 . 요컨대, 복사 여부는 여러 가지에 달려 있습니다.

You can of course avoid a copy by returning a reference. In the case of your example, returning a reference is invalid (though the compiler will allow it) because the local struct is allocated on the stack, and therefor the returned reference refers to a deallocated object. However, if the object was passed to your function (directly or as a member of an object) you can safely return a reference to it and avoid copy-on-return.

Finally, if you cannot trust copy elision and you want to avoid copies, you can use and return a unique_ptr instead of a reference. The object itself will not be copied, although the unique_ptr itself may or may not be (again, depending on copy elision!). Copying/moving a unique_ptr is however very cheap if copy elision of the unique_ptr does not happen for some reason.

Here is an example using 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();
}

Note that you must (unfortunately) declare a constructor for your struct, or else make_unique will not compile due to inadequacies of C++.


Just FYI, since in this case you are using only a struct(ure), it is the same behavior as in C language.

Though this is a language feature, it is recommended that it shall not be used


I do not agree and NOT RECOMMEND to return vector to change values: Is much faster pass as reference:

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;
}

I tested on VS2015 with following results in release mode:

By reference:8.01 MOPs and returning vector: 5.09 MOPs 60% worse!

In debug mode things are much worse:

By reference:0.053 MOPS and return vector: 0.034 MOPs

참고URL : https://stackoverflow.com/questions/1529447/does-return-statement-copy-values

반응형