문제

일부 코드를 리팩터링하는 동안 나는 std :: string을 반환하는 getter 메소드를 발견했습니다. 예를 들어 다음과 같은 것 :

class foo
{
private:
    std::string name_;
public:
    std::string name()
    {
        return name_;
    }
};

분명히 게터는 더 나은 반환 일 것입니다 const std::string&? 현재 방법은 효율적이지 않은 사본을 반환하는 것입니다. Const 참조를 반환하면 대신 문제가 발생할 수 있습니까?

도움이 되었습니까?

해결책

문제를 일으킬 수있는 유일한 방법은 발신자가 문자열을 복사하지 않고 참조를 저장하고 객체가 파괴 된 후에 사용하려고 시도하는 것입니다. 이와 같이:

foo *pFoo = new foo;
const std::string &myName = pFoo->getName();
delete pFoo;
cout << myName;  // error! dangling reference

그러나 기존 함수가 사본을 반환하므로 기존 코드를 중단하지 않습니다.

다른 팁

사실, 또 다른 문제 구체적으로 문자열을 반환하면서 ~ 아니다 참고로는 사실입니다 std::string 내부에 대한 포인터를 통해 액세스를 제공합니다 const char* TH를 통해 c_str () 방법. 이로 인해 많은 시간이 두통이 발생했습니다. 예를 들어, Foo에서 이름을 가져 와서 JNI로 전달하여 나중에 Java로 전달하기 위해 JSTRING을 구성하는 데 사용됩니다. name() 참조가 아닌 사본을 반환합니다. 나는 다음과 같은 글을 쓸 수 있습니다.

foo myFoo = getFoo(); // Get the foo from somewhere.
const char* fooCName = foo.name().c_str(); // Woops!  foo.name() creates a temporary that's destructed as soon as this line executes!
jniEnv->NewStringUTF(fooCName);  // No good, fooCName was released when the temporary was deleted.

발신자가 이런 종류의 일을하려는 경우, 일부 유형의 스마트 포인터 또는 Const Reference를 사용하는 것이 좋습니다. 이전 Java 코더는 특히 무해한 것처럼 보일 수있는 이러한 유형의 방법 체인에 특히 취약 할 수 있기 때문에 JNI를 언급합니다.

Const Reference Return의 한 가지 문제는 사용자가 다음과 같은 것을 코딩하는 경우입니다.

const std::string & str = myObject.getSomeString() ;

a std::string 반환하면, 임시 객체는 STR이 범위를 벗어날 때까지 STR에 살아 있고 str에 붙어 있습니다.

그러나 a const std::string &? 내 생각에 우리는 부모 객체가 거래 할 때 죽을 수있는 객체에 대한 참조를 가질 것입니다.

MyObject * myObject = new MyObject("My String") ;
const std::string & str = myObject->getSomeString() ;
delete myObject ;
// Use str... which references a destroyed object.

따라서 내 선호는 Const Reference Return에 간다 (어쨌든, 나는 다음 계약이 존중되는 한, 컴파일러가 추가 임시를 최적화하기를 희망하는 것보다 참조를 보내는 것이 더 편안합니다). 내 대상의 존재, 그들은 내 대상의 파괴 전에 그것을 복사한다 "

STD :: 문자열 공유 메모리의 일부 구현 COPY-ON-WRITE SENMANTICS를 통해 메모리가 있으므로 반품별로 값이 거의 효율적일 수 있습니다. 그리고 평생 문제에 대해 걱정할 필요가 없습니다 (런타임이 당신을 위해 그것을합니다).

그렇다면 성능이 걱정된다면 벤치마킹하십시오 (<= 충분히 강조 할 수 없습니다) !!! 접근 방식을 모두 시도하고 이득 (또는 그 부족)을 측정하십시오. 더 좋고 당신이 정말로 신경 쓰면 그것을 사용하십시오. 그렇지 않다면, 다른 사람들이 언급 한 평생 문제를 다시 제공하는 보호에 대한 가치를 선호합니다.

당신은 그들이 가정하는 것에 대해 무엇을 말하는지 알고 있습니다 ...

좋아, 그래서 차이 사본을 반환하고 참조를 반환하는 것 사이에 다음과 같습니다.

  • 성능: 참조를 반환하는 것은 더 빠르거나 더 빠르지 않을 수 있습니다. 그것은 방법에 달려 있습니다 std::string 컴파일러 구현에 의해 구현됩니다 (다른 사람들이 지적했듯이). 그러나 참조를 반환하더라도 함수 호출 후 과제는 일반적으로 다음과 같이 사본이 포함됩니다. std::string name = obj.name();

  • 안전: 참조를 반환하면 문제가 발생하지 않을 수도 있습니다 (끊임없이 참조). 기능의 사용자가 자신이 수행하는 작업을 알지 못하면 참조로 참조로 저장하고 제공 객체 제공 후 범위를 벗어나면 문제가 발생합니다.

당신이 그것을 원한다면 빠르고 안전합니다 사용 부스트 :: shared_ptr. 객체는 문자열을 내부적으로 저장할 수 있습니다 shared_ptr 그리고 반환 a shared_ptr. 그렇게하면 물체를 복사하지 않고 항상 안전합니다 (사용자가 원시 포인터를 꺼내지 않는 한 get() 그리고 객체가 범위를 벗어난 후에 그 일을하십시오).

나는 const std :: string &를 반환하도록 변경했다. 발신자는 모든 호출 코드를 변경하지 않으면 어쨌든 결과의 사본을 만들 것입니다. 그러나 문제는 발생하지 않습니다.

이름 () 호출 된 스레드가있는 경우 하나의 잠재적 주름이 발생합니다. 참조를 반환하지만 나중에 기본 값을 변경하면 발신자의 값이 변경됩니다. 그러나 기존 코드는 어쨌든 스레드 안전을 보이지 않습니다.

관련 잠재적 인 문제에 대한 Dima의 답변을 살펴보십시오.

발신자가 원본을 변경하려고했고 사본을 보존하기를 원했기 때문에 발신자가 실제로 사본을 원한다면 무언가를 깨뜨릴 수 있다는 것은 생각할 수 있습니다. 그러나 실제로 Const 참조를 반환해야 할 가능성이 훨씬 높습니다.

가장 쉬운 일은 시도한 다음 실행할 수있는 테스트가 있으면 여전히 작동하는지 확인하기 위해 테스트하는 것입니다. 그렇지 않다면 리팩토링을 계속하기 전에 먼저 테스트 작성에 중점을 둡니다.

그게 그렇게 중요한 건가? 최신 최적화 컴파일러를 사용하자마자, 값으로 반환하는 기능은 의미 적으로 요구되지 않는 한 사본이 포함되지 않습니다.

보다 C ++ 라이트 FAQ 이에.

Const 참조로 변경하면 해당 기능의 일반적인 사용이 중단되지 않을 것이라는 확률이 매우 좋습니다.

해당 함수 호출이 모든 코드 호출이 귀하의 제어하에있는 경우, 변경하고 컴파일러가 불평하는지 확인하십시오.

해야 할 일에 따라 다릅니다. 어쩌면 모든 발신자가 클래스를 변경하지 않고 반환 된 값을 변경하기를 원할 수도 있습니다. 날지 않는 const 참조를 반환하면.

물론 다음 주장은 발신자가 자신의 사본을 만들 수 있다는 것입니다. 그러나 함수가 어떻게 사용되는지 알고 어쨌든 발생하는 것을 알고 있다면이 작업을 수행하면 코드에서 한 걸음 더 절약 할 수 있습니다.

나는 보통 Const와 내가 할 수 없다면 반환합니다. QBZIZ는 이것이 어디에 있는지에 대한 예를 제공합니다. 물론 Qbziz는 또한 std :: string이 Copy-on-Write Semantics를 가지고 있다고 주장합니다.이 시맨틱은 다중 스레드 환경에서 많은 오버 헤드를 포함하기 때문에 오늘날 거의 사실이 아닙니다. Const를 반환함으로써 당신은 발신자에 onus를 넣어 끝에 문자열로 올바른 일을합니다. 그러나 이미 사용중인 코드를 다루고 있기 때문에 프로파일 링 이이 문자열의 복사가 막대한 성능 문제를 일으킨다는 것을 보여주지 않으면 변경해서는 안됩니다. 그런 다음 변경하기로 결정하면 아무것도 깨지지 않도록 Thouroughly를 테스트해야합니다. 바라건대 당신이 함께 일하는 다른 개발자들은 Dima의 대답과 같은 스케치를하지 않습니다.

회원에 대한 참조를 반환하면 클래스의 구현이 노출됩니다. 그것은 수업을 바꾸지 못하게 할 수 있습니다. 최적화가 필요한 경우 개인 또는 보호 된 방법에 유용 할 수 있습니다.C ++ Getter는 무엇을 반환해야합니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top