IT박스

C ++에서 "객체를 반환"하는 방법은 무엇입니까?

itboxs 2020. 6. 8. 21:12
반응형

C ++에서 "객체를 반환"하는 방법은 무엇입니까?


비슷한 질문이 많을수록 제목이 익숙한 것으로 알고 있지만 문제의 다른 측면을 요구하고 있습니다 (스택에 물건을 두는 것과 더미에 넣는 것의 차이점을 알고 있습니다).

Java에서는 항상 "로컬"객체에 대한 참조를 반환 할 수 있습니다

public Thing calculateThing() {
    Thing thing = new Thing();
    // do calculations and modify thing
    return thing;
}

C ++에서 비슷한 것을하기 위해 두 가지 옵션이 있습니다.

(1) 객체를 "반환"해야 할 때마다 참조를 사용할 수 있습니다

void calculateThing(Thing& thing) {
    // do calculations and modify thing
}

그런 다음 이렇게 사용하십시오

Thing thing;
calculateThing(thing);

(2) 또는 동적으로 할당 된 객체에 대한 포인터를 반환 할 수 있습니다

Thing* calculateThing() {
    Thing* thing(new Thing());
    // do calculations and modify thing
    return thing;
}

그런 다음 이렇게 사용하십시오

Thing* thing = calculateThing();
delete thing;

첫 번째 방법을 사용하면 수동으로 메모리를 비울 필요가 없지만 코드를 읽기가 어렵습니다. 두 번째 접근 방식의 문제는를 기억해야한다는 것 delete thing;입니다. 비효율적이므로 복사 된 값을 반환하고 싶지 않습니다 (제 생각에).

  • 세 번째 해결책이 있습니까 (값을 복사하지 않아도 됨)?
  • 첫 번째 해결책을 고수하면 문제가 있습니까?
  • 두 번째 솔루션을 언제, 왜 사용해야합니까?

비효율적이므로 복사 된 값을 반환하고 싶지 않습니다.

증명 해봐

RVO 및 NRVO 및 C ++ 0x 이동 시맨틱을 검색하십시오. 대부분의 경우 C ++ 03에서 out 매개 변수는 코드를 추악하게 만드는 좋은 방법 일 뿐이며 C ++ 0x에서는 out 매개 변수를 사용하여 실제로 상처를 입을 수 있습니다.

깨끗한 코드를 작성하고 값으로 반환하십시오. 성능에 문제가 있으면 프로파일 링 (추측 중지)하고 수정을 위해 수행 할 수있는 작업을 찾으십시오. 아마도 함수에서 물건을 반환하지 않을 것입니다.


즉, 그런 식으로 글을 쓰지 않으면 out 매개 변수를 사용하고 싶을 것입니다. 보다 안전하고 일반적으로 더 빠른 동적 메모리 할당을 피합니다. 함수를 호출하기 전에 객체를 생성 할 수있는 방법이 필요하지만 모든 객체에 항상 적합한 것은 아닙니다.

동적 할당을 사용하려면 수행 할 수있는 최소한의 방법을 스마트 포인터에 넣으십시오. (이것은 어쨌든 항상 수행되어야합니다.) 그러면 당신은 아무것도 삭제하는 것에 대해 걱정하지 않고, 예외가 안전합니다.


객체를 생성하고 반환하십시오.

Thing calculateThing() {
    Thing thing;
    // do calculations and modify thing
     return thing;
}

최적화를 잊고 읽을 수있는 코드를 작성하면 나중에 호의를 보일 것이라고 생각합니다 (나중에 프로파일 러를 실행해야하지만 사전 최적화하지는 마십시오).


다음과 같은 객체를 반환하십시오.

Thing calculateThing() 
{
   Thing thing();
   // do calculations and modify thing
   return thing;
}

이것은 Things에 대한 복사 생성자를 호출하므로 직접 구현할 수 있습니다. 이처럼 :

Thing(const Thing& aThing) {}

약간 느리게 수행 될 수 있지만 전혀 문제가되지 않을 수 있습니다.

최신 정보

컴파일러는 아마도 복사 생성자에 대한 호출을 최적화하므로 추가 오버 헤드가 없습니다. (dreamlax와 마찬가지로 의견에서 지적했습니다).


auto_ptr과 같이 스마트 포인터를 사용하려고 했습니까 (Thing이 실제로 크고 무거운 개체 인 경우).


std::auto_ptr<Thing> calculateThing()
{
  std::auto_ptr<Thing> thing(new Thing);
  // .. some calculations
  return thing;
}


// ...
{
  std::auto_ptr<Thing> thing = calculateThing();
  // working with thing

  // auto_ptr frees thing 
}

복사 생성자가 호출되는지 확인하는 빠른 방법 중 하나는 클래스의 복사 생성자에 로깅을 추가하는 것입니다.

MyClass::MyClass(const MyClass &other)
{
    std::cout << "Copy constructor was called" << std::endl;
}

MyClass someFunction()
{
    MyClass dummy;
    return dummy;
}

Call someFunction; the number of "Copy constructor was called" lines that you will get will vary between 0, 1, and 2. If you get none, then your compiler has optimised the return value out (which it is allowed to do). If you get don't get 0, and your copy constructor is ridiculously expensive, then search for alternative ways to return instances from your functions.


Firstly you have an error in the code, you mean to have Thing *thing(new Thing());, and only return thing;.

  • Use shared_ptr<Thing>. Deref it as tho it was a pointer. It will be deleted for you when the last reference to the Thing contained goes out of scope.
  • The first solution is very common in naive libraries. It has some performance, and syntactical overhead, avoid it if possible
  • Use the second solution only if you can guarantee no exceptions will be thrown, or when performance is absolutely critical (you will be interfacing with C or assembly before this even becomes relevant).

I'm sure a C++ expert will come along with a better answer, but personally I like the second approach. Using smart pointers helps with the problem of forgetting to delete and as you say, it looks cleaner than having to create an object before hand (and still having to delete it if you want to allocate it on the heap).

참고URL : https://stackoverflow.com/questions/3350385/how-to-return-an-object-in-c

반응형