복사본 대신 객체에 대한 const 참조 반환
일부 코드를 리팩토링하는 동안 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
그러나 기존 함수가 복사본을 반환하므로 기존 코드를 손상시키지 않습니다.
실제로 참조가 아닌 문자열을 반환하는 것과 관련된 또 다른 문제 는 c_str () 메서드 를 통해 내부에 대한 포인터를 통해 액세스를 제공 한다는 사실입니다 . 이로 인해 많은 시간 동안 디버깅 문제가 발생했습니다. 예를 들어, foo에서 이름을 가져 와서 JNI에 전달하여 나중에 Java로 전달할 jstring을 구성 하고 참조가 아닌 복사본을 반환 한다고 가정 해 보겠습니다 . 다음과 같이 작성할 수 있습니다.std::string
const char*
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 참조를 사용하거나 최소한 foo.name () 메서드에 대해 불쾌한 경고 주석 헤더를 사용하는 것이 더 나을 수 있습니다. JNI를 언급하는 이유는 이전의 Java 코더가 다른 방법으로는 무해 해 보일 수있는 이러한 유형의 메소드 체인에 특히 취약 할 수 있기 때문입니다.
const 참조 반환에 대한 한 가지 문제는 사용자가 다음과 같이 코딩 한 경우입니다.
const std::string & str = myObject.getSomeString() ;
A를 std::string
STR이 범위를 벗어나까지 반환, 임시 객체는 살아 STR에 부착 남아있을 것입니다.
하지만 어떻게 const std::string &
되나요? 내 생각 엔 부모 객체가 할당을 해제 할 때 죽을 수있는 객체에 대한 const 참조가있을 것입니다.
MyObject * myObject = new MyObject("My String") ;
const std::string & str = myObject->getSomeString() ;
delete myObject ;
// Use str... which references a destroyed object.
그래서 내 선호는 const 참조 반환 (어쨌든, 컴파일러가 추가 임시를 최적화하기를 바라는 것보다 참조를 보내는 것이 더 편하기 때문입니다), 다음 계약이 존중되는 한 : "만약 당신이 그것을 넘어서 원한다면 내 개체의 존재, 내 개체가 파괴되기 전에 복사합니다. "
기록 중 복사 의미와 표준 : : 문자열 공유 메모리의 구현에, 그래서 복귀에 의해 값이 리턴에 의해 참조 거의 효율적이 될 수 및 런타임 않습니다 (당신은 평생 문제에 대해 걱정할 필요가 없습니다 당신을 위해).
성능이 걱정되면 벤치마킹하십시오 (<= 충분히 강조 할 수 없습니다) !!! 두 가지 방법을 모두 시도하고 이득 (또는 부족)을 측정하십시오. 하나가 더 낫고 당신이 정말로 관심이 있다면 그것을 사용하십시오. 그렇지 않다면 다른 사람들이 언급 한 평생 문제를 제공하는 보호를 위해 가치를 선호합니다.
당신은 그들이 가정에 대해 말하는 것을 알고 있습니다 ...
좋습니다 . 복사본 반환과 참조 반환 의 차이점 은 다음과 같습니다.
성능 : 참조를 반환하는 것이 더 빠르거나 빠르지 않을 수 있습니다.
std::string
(다른 사람들이 지적했듯이) 컴파일러 구현에 의해 구현되는 방법에 따라 다릅니다 . 그러나 참조를 반환하더라도 함수 호출 후 할당에는 일반적으로 복사가 포함됩니다.std::string name = obj.name();
안전성 : 참조를 반환하면 문제가 발생할 수도 있고 그렇지 않을 수도 있습니다 (댕글 링 참조). 함수의 사용자가 자신이 무엇을하는지 모르면 참조를 참조로 저장하고 제공하는 객체가 범위를 벗어난 후에 사용하면 문제가 있습니다.
당신이 그것을 원하는 경우 신속하고 안전하게 사용 부스트 :: shared_ptr을을 . 개체는 내부적으로 문자열을 저장할 수있는 shared_ptr
과를 반환합니다 shared_ptr
. 이렇게하면 개체가 복사되지 않고 항상 안전합니다 (사용자가 원시 포인터를 get()
꺼내 개체가 범위를 벗어난 후에 작업을 수행하지 않는 한).
const std :: string & 반환하도록 변경합니다. 호출 코드를 모두 변경하지 않으면 호출자가 결과의 복사본을 만들 수 있지만 문제가 발생하지는 않습니다.
name ()을 호출하는 여러 스레드가있는 경우 잠재적 인 주름이 발생합니다. 참조를 반환했지만 나중에 기본 값을 변경하면 호출자의 값이 변경됩니다. 그러나 기존 코드는 어쨌든 스레드로부터 안전하지 않습니다.
관련 가능성이 있지만 가능성이없는 문제에 대한 Dima의 답변을 살펴보십시오.
호출자가 원본을 변경하려고하고 복사본을 보존하기를 원했기 때문에 호출자가 실제로 복사본을 원하면 무언가를 깰 수 있다고 생각할 수 있습니다. 그러나 실제로는 const 참조를 반환해야 할 가능성이 훨씬 더 높습니다.
The easiest thing to do is try it and then test it to see if it still works, provided that you have some sort of test you can run. If not, I'd focus on writing the test first, before continuing with refactoring.
Does it matter? As soon as you use a modern optimizing compiler, functions that return by value will not involve a copy unless they are semantically required to.
See the C++ lite FAQ on this.
Odds are pretty good that typical usage of that function won't break if you change to a const reference.
If all of the code calling that function is under your control, just make the change and see if the compiler complains.
Depends what you need to do. Maybe you want to all the caller to change the returned value without changing the class. If you return the const reference that won't fly.
Of course, the next argument is that the caller could then make their own copy. But if you know how the function will be used and know that happens anyway, then maybe doing this saves you a step later in code.
I normally return const& unless I can't. QBziZ gives an example of where this is the case. Of course QBziZ also claims that std::string has copy-on-write semantics which is rarely true today since COW involves a lot of overhead in a multi-threaded environment. By returning const & you put the onus on the caller to do the right thing with the string on their end. But since you are dealing with code that is already in use you probably shouldn't change it unless profiling shows that the copying of this string is causing massive performance problems. Then if you decide to change it you will need to test thouroughly to make sure you didn't break anything. Hopefully the other developers you work with don't do sketchy stuff like in Dima's answer.
Returning a reference to a member exposes the implementation of the class. That's could prevent to change the class. May be usefull for private or protected methods incase the optimization is needed. What should a C++ getter return
'Program Tip' 카테고리의 다른 글
Dockerfile에서 스크립트 실행 (0) | 2020.11.01 |
---|---|
Jenkins 용 API 토큰을 얻는 방법 (0) | 2020.11.01 |
디렉토리에 응용 프로그램 바로 가기 만들기 (0) | 2020.11.01 |
Mercurial에서 git reset --hard HEAD를 어떻게합니까? (0) | 2020.11.01 |
'int main () {return (0);의 부동 소수점 예외 (SIGFPE) (0) | 2020.11.01 |