IT

함수에서 '벡터'를 반환해도되는 이유는 무엇입니까?

lottoking 2020. 8. 10. 07:28
반응형

함수에서 '벡터'를 반환해도되는 이유는 무엇입니까?


이 코드를 고려하십시오. 이 유형의 코드를 여러 번 보았습니다. words로컬 벡터입니다. 함수에서 어떻게 반환 할 수 있습니까?

죽지 않을 것견 보장 보장 할 수 있습니까?

 std::vector<std::string> read_file(const std::string& path)
 {
    std::ifstream file("E:\\names.txt");

    if (!file.is_open())
    {
        std::cerr << "Unable to open file" << "\n";
        std::exit(-1);
    }

    std::vector<string> words;//this vector will be returned
    std::string token;

    while (std::getline(file, token, ','))
    {
        words.push_back(token);
    }

    return words;
}

죽지 않을 것견 보장 보장 할 수 있습니까?

참조가 반환되지 않는 한 그렇게해도 괜찮습니다. words결과를받는 변수로 이동합니다.

지역 변수가 범위를 벗어납니다. 이동 (또는 복사) 후.


C ++ 11 이전 :

이 함수는 지역 변수를 반환하지 않고 복사본을 반환합니다. 그러나 컴파일러는 실제 복사 작업이 수행되지 않는 작업을 수행 할 수 있습니다.

자세한 내용은 이 질문 및 답변 을 참조하십시오.

C ++ 11 :

함수는 값을 이동합니다. 자세한 내용은 이 답변참조 하십시오.


함수에서 배열을 반환하는 것이 허용되지 않을 경우 예상대로 작동하지 않는다는 C (및 C ++)의 문제를 해결하고 있다고 생각합니다. 이 배열 반환이 간단한 형식) 스택의 실제 배열에 대한 포인터를 반환 한 다음 함수가 반환 될 때 즉시 제거됩니다.

그러나이 경우에는 std::vector은 클래스이고, 같은 클래스는 호출자 호출에 복사 될 수 있기 때문에 작동합니다 . [사실, 대부분의 컴파일러는 "반환 값 최적화"라는 것을 사용하여 특정 유형의 복사를 최적화합니다. 특히 함수에서 반환 될 때 큰 개체를 복사하지 않도록하기 위해 도입 된 것이지만 이는 최적화이며 프로그래머의 관점에서 볼 때에 할당 할 할당 호출 된 것처럼 동작]

참조를 반환하지 않는 한 괜찮습니다.


동작을 잘 이해하기 위해 다음 코드를 사용할 수 있습니다.

#include <iostream>

class MyClass
{
  public:
    MyClass() { std::cout << "run constructor MyClass::MyClass()" << std::endl; }
    ~MyClass() { std::cout << "run destructor MyClass::~MyClass()" << std::endl; }
    MyClass(const MyClass& x) { std::cout << "run copy constructor MyClass::MyClass(const MyClass&)" << std::endl; }
    MyClass& operator = (const MyClass& x) { std::cout << "run assignation MyClass::operator=(const MyClass&)" << std::endl; }
};

MyClass my_function()
{
  std::cout << "run my_function()" << std::endl;
  MyClass a;
  std::cout << "my_function is going to return a..." << std::endl;
  return a;
}

int main(int argc, char** argv)
{
  MyClass b = my_function();

  MyClass c;
  c = my_function();

  return 0;
}

출력은 다음과 가변합니다.

run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run constructor MyClass::MyClass()
run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run assignation MyClass::operator=(const MyClass&)
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()

하지 동의 않으며 다음 을 반환 하지 않는 것이 좋습니다vector .

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

이것은 훨씬 더 빠 사용합니다.

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

릴리스 모드에서 다음 결과로 Visual Studio 2017에서 테스트했습니다.

참조에 의한 8.01 MOP
5.09 MOP 반환 벡터

디버그 모드에서는 상황이 훨씬 더 나빠집니다.

0.053 MOPS (참조 기준)
0.034 MOP (반환 벡터 기준)


이것은 실제로 디자인의 실패입니다. 상대적으로 사소하지 않은 것에 대해 원시적이지 않은 것에 대해 반환 값을 사용해서는 안됩니다.

이상적인 솔루션은 참조 / 포인터에 대한 결정과 설명 자로 "const \ 'y \'ness"를 적절하게 사용하여 반환 매개 변수를 통해 구현되어야합니다.

또한 C 및 C ++의 배열에있는 레이블은 사실상 포인터이며 해당 구독은 사실상 오프셋 또는 추가 기호라는 사실을 알아야합니다.

따라서 레이블 또는 ptr array_ptr === 배열 레이블은 따라서 foo [offset]을 반환하는 것은 실제로 메모리 포인터 위치의 반환 요소 foo + 유형 반환 유형의 오프셋을 말합니다.

참고 URL : https://stackoverflow.com/questions/22655059/why-is-it-ok-to-return-a-vector-from-a-function

반응형