2012-10-17 6 views
2

나는 rvalue 레퍼런스가 클래스의 디자인에 어떻게 영향을 주는지 평가하려고했다. 장소를 rvalue 참조와평평한 참조와 클래스 디자인

//another module 
{ 

    string configvalue; 
    X x; 

    //read configvalue from a file and call set 

    ... 
    x.set_data(configvalue.c_str()); 

    //use x to do some magic 
    .. 
    ... 


} 

이 더 나은 것 때문에

처럼 다른 멤버 함수를 제공하기 위해 :이 클래스는 다음과 같은 다른 모듈에 의해 사용되는

class X 
{ 
    string internal; 

public: 
    void set_data(const char* s) 
    { 
     internal = s; 
    } 
.. 
.. 
.. 
//other stuff 

}; 

아래와 같이 나는 기존의 클래스가 말

class X 
{ 
... 
... 
.... 
void set_data(string s) 
{ 
    internal = std::move(s); 
} 
}; 

이렇게하면이 클래스의 클라이언트는 이동 의미 체계를 사용하고 사용 당 하나의 할당/복사 작업 집합을 방지 할 수 있습니다. 이것은 매우 복잡한 예이지만 '최소 인터페이스'패러다임을 깨지 않고 모든 클래스 디자인에 동일한 원리가 적용됩니다.

이 문제에 대한 통찰력이 있으면 대단히 감사하겠습니다.

답변

-1

void set_data(const char* s)void set_data(string s)이 인터페이스의 일부로 표시되지 않습니다. 이로 인해 모호함이 생기고 부작용이 발생하기 쉽습니다. 게다가, 당신은 여전히 ​​set_data(string s)에 전화하여 값으로 인수를 전달합니다. 대신에 나는이 다음 funcs 정의 제안 :

void set_data(const string &s); 
void set_data(string &&s); 

당신이이 rvalue을 이후 깊은 문자열의 내부를 훔칠 수있는 문자열과 두 번째 복사합니다 첫째, 2 구현을 할 수 있습니다이 방법을 (두고 있는지 확인 정의 된 상태에서 소멸자가 문제없이 파기 할 수 있도록 - 자세한 내용은 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics 참조). 인수가 std::move 예를 들어, rvalue에 강제되는 경우

번째 버전

rvalue string 인수에 자동으로 중 호출 또는됩니다.

by-value 옵션을 사용하려는 경우 문자열 복사 생성자 set_data(string(str))과 결합 된이 API의 rvalue 버전을 사용할 수 있습니다.

+1

제안 사항을 코딩 했습니까? –

+0

@HowardHinnant 아니요. – SomeWittyUsername

+0

예. 처음 두 개의'set_data'를 구현하고 rvalue'string'을 호출 할 때, 제 컴파일러는 모호함을 호소합니다. 세 번째'set_data' 오버로드를 추가 할 때, lvalue'string'을 호출 할 때 모호함을 갖습니다. –

4

예, 권장하는대로 과도한 수를 입력하십시오 .은 좋은 아이디어입니다. rvalue가 없더라도 그러한 오버로드를 참조하는 것이 좋습니다.

x.set_data(s); 

이 훨씬 더 직관적 인 (그리고 조금이라도 더 효율적으로) X의 클라이언트입니다

x.set_data(s.c_str()); 

반면, 그렇지 않으면,해야 그것을 사용하려면 std::string s을 부여.

또 다른 옵션으로,이 두 오버로드를 추가 할 수 있습니다

void set_data(const string& s) {internal = s;} 
void set_data(string&& s)  {internal = std::move(s);} 

이 올바르게 제시하는 하나의 과부하와 거의 동일합니다. 두 가지 과부하 솔루션에는 성능상의 이점이 거의 없습니다. 단일 과부하 솔루션은 인수가 xvalue (std::move으로 캐스팅 된 왼쪽 값) 일 때 여분의 string 이동 구성을 필요로합니다. 그러나 std::string의 이동 생성자는 정말 빠릅니다. 따라서 큰 문제는 아닙니다. 나는 그것을 완전 공개의 정신으로 만 언급한다.

set_data에 둘 이상의 매개 변수가있는 경우 "by-value"접근 방식이 훨씬 매력적입니다. 예를 들어 string 두 개를 전달해야하는 경우를 생각해보십시오. 귀하의 선택 사항은 다음과 같습니다

해결 방법 1

void set_data(string s1, string s2); 

해결 방법 2

void set_data(const string& s1, const string& s2); 
void set_data(  string&& s1, const string& s2); 
void set_data(const string& s1,  string&& s2); 
void set_data(  string&& s1,  string&& s2); 

빠르게 볼 수 있듯이, 매개 변수의 수를 2 저울 제대로 해결.

마지막으로, 어떠한 경우에 동일한 유형의 두 솔루션을 적용하려고한다 :

이 작업을 수행하지 마십시오!

void set_data(string s)  {internal = std::move(s);} 
void set_data(const string& s) {internal = s;} 
void set_data(string&& s)  {internal = std::move(s);} 

이 오버로드 집합은 모호합니다. 그냥 03 ++ C에서와 같이 다음과 같은 두 가지 오버로드가 모호 : 참조 값에 의한 과부하

void set_data(string s)  {internal = std::move(s);} 
void set_data(const string& s) {internal = s;} 

결코 어느 좌변 참조도를 rvalue 참조.

+0

void set_data (string && s) {internal = std :: move (s);}', 언제 처음 호출 되나요? –

+0

첫 번째 버전은 lvalues에 바인딩하는 것을 선호합니다 ... 두 번째 버전은 rvalues와 lvalues를'std :: move'로 래핑하는 것을 선호합니다. – Jason

+0

여러 매개 변수 전달과 관련하여 - 예, 불규칙한 비율로 조정되지만 이것이 "가치있는"방법을 선택하는 이유가되어서는 안됩니다. 오버로드 된 함수를 참조하여 전달되는 단일 구성 객체에 인수를 저장하여 쉽게 해결할 수 있습니다 (설계상의 고려 사항 일 것임) - 단일 인수로 원래의 문제로 문제를 줄임 – SomeWittyUsername