2013-10-21 2 views
2

나는 여전히 C++ 11의 이동 및 평가 절의 의미 개념을 배우고 있음을 이해해주십시오. 제 질문은 레거시 코드가 단순히 C++ 11 컴파일러와 STL을 사용하여 불필요한 복사본을 피하는 무료 점심을 먹을 수 있는지 여부입니다.C++ 11 rvalue and move : 레거시 코드가 복사본을 피할 수 있습니까?

다음은 매우 간단한 예입니다. 이 코드는 주어진 문자열에 대한 간단한 문자 빈도 테이블을 만듭니다. 예를 들어, "apple"은 {('a', 1), ('e', 1), ('l', 1), ('p', 2)}을 반환해야합니다. 보시다시피, 저는 벡터를 값으로 사용하고 있습니다.

typedef std::tuple<char, int> Frequency; 
typedef std::vector<Frequency> Frequencies; 

Frequencies buildFrequenciesTable(std::string w) { 
    char table['z' - 'a' + 1] = { 0, }; 
    std::for_each(w.cbegin(), w.cend(), [&table](char c) { 
    ++table[::tolower(c) - 'a']; 
    }); 

    Frequencies freqs; 
    for (size_t i = 0; i < 'z' - 'a' + 1; ++i) { 
    if (table[i] != 0) 
     freqs.push_back(tuple<char, int>((char) ('a' + i), table[i])); 
    } 
    return freqs; // Q1: Is vector get copied? 
} 

int main() { 
    using namespace std; 

    Frequencies f1 = buildFrequenciesTable("apple"); // Q2: Copy? 
    Frequencies f2 = buildFrequenciesTable("banana"); 
    vector<Frequencies> fs = { f1, f2 }; // Q3: Copy? 
} 

이 값으로 벡터를 반환 할 때 C++ 03의 모든 사본 코드 (사용하는 복사 생성자와 대입 연산자)를 생성하는 것이 분명하다. C++ 11에서는 어떻습니까? std::vector에는 이동 생성자가 있습니다. 이 코드가 unnessarry 복사본을 피할 수 있습니까? 또는 위의 코드에서 && 또는 std::forward을 사용해야합니까?

내부 STL 코드를 디버깅하려고 시도했지만 설득하기가 어려웠습니다.

참고 : 제 목표는 이러한 기능에서 불필요한 사본을 최소화하는 것입니다. 새로운/포인터/참조를 사용할 수 있지만 메모리 누수 문제를 해결해야합니다. 그래서 저는 가능한 한 많은 가치들을 사용하고 싶습니다.

답변

5

Q1의 경우 "NRVO (Named Return Value Optimization)"에 의해 복사본이 제거되므로 C++ 03에서도 복사 할 가능성이 거의 없습니다.

Q2의 경우 copy-elision이 제거하므로 C++ 03에서도 복사 할 가능성이 거의 없습니다. 심지어 C++ 11에서 3 분기 들어

, 당신은 당신이 순서대로 이동 등 f1f2을 표시해야하는 것처럼이 사본을 할 에 실제로 이동이 :

vector<Frequencies> fs = { std::move(f1), std::move(f2) }; 

여러 질문을하기 때문에 더 자세한 설명을 생략하고 NRVO, copy-elision을 찾아보고 std::move이 필요한 경우 더 궁금한 점이 있는지 물어보십시오.

이동 될 수있는 임시가있는 경우 그러나, 당신은 예를 들어 무료 이동을 얻을 것이다 경우가 있습니다

vector<Frequencies> fs = { buildFrequenciesTable("apple"), 
          buildFrequenciesTable("bananas") }; 

위의 두 벡터가 임시직으로 buildFrequenciesTable()에서 반환하기 때문에 그들이 감지 것 fs으로 이동합니다.

+0

고마워요! 따라서 Q1과 Q2의 경우에는 기본적으로 C++ 11의 r 값 참조 및 이동 의미에 따른 이점이 없습니다. 나는 정확하게 이해하고 있는가? – Nullptr

+0

내 목표는 실제로 이러한 기능에서 불필요한 사본을 최소화하는 것입니다. 나는 새로운/포인터/참조를 사용할 수 있지만 이것은 미친 누출 문제가 필요할 것입니다. 그래서 저는 가능한 한 많은 가치들을 사용하고 싶습니다. – Nullptr

+0

또 하나의 하위 질문 (어리석은 질문 일 수 있음) :이 코드를 더욱 최적화 할 수 있습니까? 예를 들어,'BuildFrequenciesTable'에'Frequencies &&'를 반환하거나'Frequencies && f1'을 선언 할 수 있습니다. 특히 위의'f1'과'f2'는 변경되지 않습니다. – Nullptr

1

(Q1)에서 벡터를 반환하면 가능한 경우 코드를 수정할 필요없이 이동 의미 체계가 사용됩니다. 마찬가지로 반환 된 임시 (Q2)에서 벡터를 초기화하면 이동 의미가 사용됩니다. 반환 값은 의 값인이므로 이동할 수 있습니다. 실제로는 이동 또는 복사없이 기능을 f1f2으로 직접 초기화 할 수 있도록 두 동작 (또는 역사적으로 복사본)을 생략해야합니다.

벡터 (Q3)에 넣으면 복사가 필요합니다. 변수는 암시 적으로 이동할 수없는 값인입니다. 따라서 이러한 사본을 피하려면 std::move을 사용하거나 코드를 재구성해야합니다.

관련 문제