2012-04-14 4 views
18

일반적으로 범위 기반 for 루프의 임시 수명 시간이 전체 루프까지 확장된다는 것을 알고 있습니다 (나는 C++11: The range-based for statement: "range-init" lifetime?을 읽었습니다). 이런 따라서하고 물건은 일반적으로 OK입니다 : 여기범위 기반의 임시 객체

#include <iostream> 
#include <QList> 

int main() { 
    for (auto i : QList<int>{} << 1 << 2 << 3) 
    std::cout << i << std::endl; 
    return 0; 
} 

문제 : 지금은 내가 Qt의 QList 컨테이너와 유사한 것으로 생각 뭔가를하려고 할 때 메모리 문제에 대한 걸림돌있어

for (auto &thingy : func_that_returns_eg_a_vector()) 
    std::cout << thingy; 

valgrind가 QList 클래스의 어딘가에 잘못된 메모리 액세스를 표시한다는 것입니다. 그러나 목록이 변수에 저장되도록 예를 수정하는 것은 올바른 결과를 제공합니다

이제 내 질문입니다
#include <iostream> 
#include <QList> 

int main() { 
    auto things = QList<int>{} << 1 << 2 << 3; 
    for (auto i : things) 
    std::cout << i << std::endl; 
    return 0; 
} 

: 나는 예를 들어, 결과 첫 번째 경우에 바보 같은 일을하고 있어요 정의되지 않은 동작 (나 자신을 위해 이것을 대답하기 위해 C++ 표준을 읽는 데 충분한 경험이 없습니다)? 또는이 문제가 QList을 사용하는 방법 또는 QList이 구현되는 방법과 관련된 문제입니까?

답변

12

C++ 11을 사용하고 있으므로 you could use initialization list instead입니다. 이 Valgrind의 전달합니다 :

int main() { 
    for (auto i : QList<int>{1, 2, 3}) 
    std::cout << i << std::endl; 
    return 0; 
} 

문제는 전혀 관련이없는 경우에도 C++ (11) 또는 범위를 기반으로 할 수 있습니다.

QList<int>& things = QList<int>() << 1; 
things.end(); 

나 : 다음 코드는 같은 문제를 보여줍니다

#include <iostream> 

struct S { 
    int* x; 

    S() { x = NULL; } 
    ~S() { delete x; } 

    S& foo(int y) { 
     x = new int(y); 
     return *this; 
    } 
}; 

int main() { 
    S& things = S().foo(2); 
    std::cout << *things.x << std::endl; 
    return 0; 
} 

유효하지 않은 읽기 식 S() (또는 QList<int>{})에서 임시 객체가 C 다음과 같은 선언 (후 파괴되기 때문입니다 ++ 03 및 C++ 11 §12.2/5) 컴파일러는 foo() (또는 operator<<) 메서드가 해당 임시 객체를 반환하지 않는다는 것을 알지 못하기 때문입니다. 따라서 이제 해제 된 메모리의 내용을 참조하고 있습니다.

+0

감사 명확한 설명. 그리고 어리석은 저, 당연히 나는 초기화 목록을 처음부터 사용 했어야합니다 - 어떻게 든 간단히 생각하지 않았습니다. 아마 Qt의 예제 때문에 비슷한 경우에 항상'<<'을 사용하기 때문입니다. –

+0

아, C++ 11 지원은 Qt 4.8 이상에서만 사용할 수 있습니다. 그러나 이와 같은 경우에는 대신 표준 라이브러리의 컨테이너를 쉽게 사용할 수 있습니다. –

+0

이 문제는 'QList const &'(즉,for (auto i : static_cast const &> (QList {} << 1 << 2 << 3))')? 이런 식으로'__' 루프 초기화에서 const 참조에 바인딩 될 것입니다, 만약 제가 §6.5.4를 올바르게 읽었다면, 차례대로 임시 수명 시간이 루프의 범위로 확장 될 것입니다. –

6

컴파일러는 아마도 operator << 세 호출의 결과입니다 참조가 임시 객체 QList<int>{}에 바인딩, 그래서 임시의 수명이 연장되지 않는다는 것을 알 수 없다. 컴파일러는 함수의 반환 값에 대해 함수의 형식을 제외하고는 알지 못합니다 (알 수 없습니다). 참조 인 경우 바인딩에 무엇이 있는지 모릅니다. 평생 규칙을 적용하려면 바인딩이 직접적이어야한다고 확신합니다.

목록이 더 이상 임시 때문이 작동 안 :

#include <iostream> 
#include <QList> 

int main() { 
    auto things = QList<int>{}; 
    for (auto i : things << 1 << 2 << 3) 
    std::cout << i << std::endl; 
    return 0; 
} 

을 그리고 바인딩이 직접하기 때문에이 일을해야하기 때문에 규칙을 적용 할 수 있습니다

#include <iostream> 
#include <QList> 

int main() { 
    for (auto i : QList<int>{1, 2, 3}) 
    std::cout << i << std::endl; 
    return 0; 
} 
관련 문제