2016-12-30 5 views
1

예를 들어 이동 의미를 지원하는 std::list을 사용합니다.임시 개체를 현재 위치로 지정하는 작업을 줄이면

std::list<std::string> X; 
... //X is used in various ways 
X=std::list<std::string>({"foo","bar","dead","beef"}); 

컴파일러는 C++ (11) 이후 임무를 수행하기위한 가장 간단한 방법은 다음과 같습니다

  1. X
  2. X

std::list

  • 이동 std::list를 구성 파괴 자, 컴파일러는 f를 할 수 없습니다. 대신에 따르게 :

    1. 는 X
    2. 에게 현재 위치에서

    이 분명히 다른 memcpy을 절약하면서 할당을 제거하기 때문 contruct std::list을 파괴한다. 두 번째 행동을 가능하고 유용하게 만드는 편리한 방법은 무엇입니까? C++의 차기 버전에서 계획 되었습니까?

    내 생각 엔 C++는 여전히 쓰기를 제외하고 제공하지 않는다는 것입니다 :

    X.~X(); 
    new(&X) std::list<std::string>({"foo","bar","dead","beef"}); 
    

    내가 맞죠?

  • +1

    QList의 기능을 모르는 사람들을 위해 std :: list를 사용하지 않는 것이 좋습니다. –

    +1

    @livedeveloper :'QList'는 포인터의 배열이고'std :: list'는 링크 된리스트이기 때문에. 이들은 서로 다른 할당 속성을 가진 매우 다른 유형입니다. –

    +0

    @NicolBolas :'QList'는 전적으로 demostratively 사용됩니다, 그것의 속성은별로 중요하지 않습니다. 그들의 요점은 유효합니다. –

    답변

    2

    실제로 연산자 =를 정의하여 이니셜 라이저 목록을 만들 수 있습니다. 표준 : : 목록은, 당신의 경우

    X = {"foo","bar","dead","beef"}. 
    

    를 호출, 어떤 일이되었다 실제로 :

    1. 임시
    와 X의 임시
  • 전화 이동 할당 연산자를 구축

    std :: list와 같은 대부분의 객체에서 이것은 단순히 객체를 구성하는 것보다 비싸지 않습니다.

    그러나 두 번째 std :: list의 내부 저장소에 대한 추가 할당이 여전히 발생하므로 가능한 경우 X에 할당 된 내부 저장소를 다시 사용할 수 있습니다. 어떤 happenning되어 있습니다 :

    1. 구성 : 임시의 요소에 대한 약간의 공간을 할당
    2. 이동 : 포인터가 X로 이동; 이전에 X가 사용하는 공간은

    일부 개체가 초기화 목록을 취할 수있는 할당 연산자를 오버로드 해제, 그리고 std::vectorstd::list의 경우입니다. 이러한 운영자는 이미 내부적으로 할당 된 저장소를 사용할 수 있습니다.이 저장소는 여기에서 가장 효과적인 솔루션입니다.

    // 당신이 이동 할당을 포함하는 문이있을 때 여기

  • +0

    QList는'std :: list'로 바뀌 었습니다. –

    +0

    감사합니다. 이니셜 라이저 목록 할당 연산자는 std :: list와 함께 작동합니다. 나는 –

    +0

    을 편집 할 것입니다. "여기 조숙 한 최적화에 대해 평소와 같이 적어주세요."- C++은 성능 지향 언어이며 오버 헤드를 최소화하는 방법을 항상 흥미롭게 보았습니다. –

    1

    향후 C++ 버전에서 계획 되었습니까?

    아니요.

    할당은 이 아니며은 destroy-then-create와 동일합니다. X은 할당 예제에서 소멸되지 않습니다. X은 실시간 개체입니다. 내용이X이 파괴 될 수 있지만 X은 절대로 존재하지 않습니다. 도 아니고이어야합니다.

    X을 파괴하려면 explicit-destructor-and-placement-new를 사용하는 능력이 있어야합니다. const 회원의 가능성으로 인해 안전을 원할 경우 객체에 대한 포인터를 세탁해야합니다. 그러나 할당은 이 아니어야합니다.은 이와 동등한 것으로 간주됩니다.

    효율성이 염려되는 경우 assign 멤버 함수를 사용하는 것이 훨씬 좋습니다. assign을 사용하면 X에 기존 할당을 다시 사용할 수 있습니다. 그리고 이것은 거의 확실히 당신의 "파괴 + 플러스 - 구조"버전보다 더 빠를 것입니다. 연결된 목록을 다른 객체로 옮기는 데 드는 비용은 간단합니다. 그러한 할당을 모두 다시 할당하는 데 드는 비용은 그렇지 않습니다.

    이것은 특히 std::list의 경우 중요하며, 로트 할당이 있습니다.

    최악의 시나리오 인 assign은 수업 외의 다른 어떤 것보다 효과적 일 수 있습니다. 그리고 최상의 경우, 훨씬 더 좋을 것입니다.

    +0

    필자는 줄을 추가하고 동일한 수동 파괴 및 원시 포인터를 사용하지 않고 반환 객체를 생성하는 함수를 작성하는 것이 더 이상 불가능합니다. 그 점을 분명히 해줄 수 있습니까? –

    +0

    그게 원래 질문의 큰 스트레칭일지도 모르지만 ... –

    1

    조기 최적화에 대한 일반적인 두서를 넣으십시오 : 소멸자가 이동하기 전에 x에 대한 호출되지 않습니다

    x = std::move(y); 
    

    합니다. 그러나 이동 후에는 소멸자가 y으로 호출됩니다. 이동 할당 연산자의 기본 개념은 y의 내용을 에 y의 저장소에 대한 포인터를 복사하는 것과 같이 간단한 방법으로 x으로 이동할 수 있다는 것입니다. 또한 이전 내용이 제대로 파괴되었는지 확인해야합니다. y을 더 이상 사용할 수 없으며 y의 소멸자가 호출된다는 것을 알고 있기 때문에 이것을 y으로 바꿀 수도 있습니다.

    이동 지정이 인라인되면 컴파일러는 y에서 x으로 이동 저장소에 필요한 모든 작업이 현재 위치 구성과 동일하다는 것을 추론 할 수 있습니다. 당신의 마지막 질문을 다시

    +0

    따라서 이동 생성자는 소멸자의 일부를 다시 구현해야합니까? –

    +0

    과제가 인라인 될 수는 있지만 여전히 인스 멘트 건설이되지 않는다는 것을 알고 있습니까? –

    +1

    move * assignment * 연산자에 대해 얘기하고있었습니다. move * constructor *과 다릅니다. 어쨌든 이동 할당 연산자는 LHS 자체를 파괴하거나 RHS로 스와핑하도록 선택할 수 있습니다. RHS에서 호출되는 소멸자에 의존 할 수 있기 때문입니다. –

    1

    내가 맞죠?

    허용되는 것에 대한 귀하의 아이디어가 잘못되었습니다. 컴파일러는 관찰 가능한 효과를 유지하는 한 모든 최적화를 대체 할 수 있습니다. 이것을 "있는 그대로"규칙이라고합니다. 가능한 최적화에 영향을주지 않으면 모든 코드를 제거하는 것이 포함됩니다. 특히, 두 번째 예제의 "허용되지 않음"은 완전히 거짓이며, "할당을 제거합니다"라는 추론은 첫 번째 예제에도 적용됩니다. 즉, 반대 결론을 이끌어냅니다. 바로 거기에 자체 모순이 있습니다.