2011-02-01 4 views
22

나는 리눅스 & 윈도우 모두에 대해 응용 프로그램을 작성 중이며 GCC 빌드가 복사 생성자에 쓸모없는 호출을 많이 생성하고 있음을 알 수 있습니다. 이 시험은 불과 3 개 요소의 벡터를 생성표준 라이브러리 컨테이너에서 GCC의 여러 값을 복사합니다

struct A 
{ 
    A()    { std::cout << "default" << std::endl; } 
    A(A&& rvalue)  { std::cout << "move" << std::endl; } 
    A(const A& lvalue) { std::cout << "copy" << std::endl; } 
    A& operator =(A a) { std::cout << "assign" << std::endl; return *this; } 
}; 

BOOST_AUTO_TEST_CASE(test_copy_semantics) 
{ 
    std::vector<A> vec_a(3); 
} 

:

다음은이 동작을 생산하는 예제 코드입니다. 난 A lvalues가 없기 때문에 3 개의 기본 생성자 호출과 0 개의 복사본을 기대합니다. 비주얼 C++ 2010

는 출력이다

은 GCC 4.4.0 (는 MinGW)에서
default 
move 
default 
move 
default 
move 

(-O2 -std =는 C++ 0X), 출력은 :

default 
copy 
copy 
copy 

무슨 일이 벌어지고 있으며 어떻게 수정합니까? 사본은 실제 수업에 비쌉니다. 기본 건설과 이동은 저렴합니다.

+1

''헤더를 보았습니까? 생성자는 무엇을하고 있습니까? GCC의 동작은 객체가 디폴트로 생성 된 후 N 번 복사되는 C++ 03 스펙과 일치합니다. 기본 라이브러리의 버전이 C++ 0x에 추가 된 새 생성자를 지원하지 않을 수도 있습니다.이 생성자는 기본적으로 N 개의 요소를 생성합니다. –

+1

이 예제에서는 C++ 0x 언어 기능을 사용하기 때문에 C++ 0x 사양이 아니라 C++ 03 사양에 대한 질문이라고 가정합니다. –

+1

GCC 4.5와 동일한 출력 – tstenner

답변

18

두 가지 구현 (Visual C++ 2010 및 GCC 4.4.0)에 오류가 있습니다. 올바른 출력은 다음

이/4 23.3.5.1 [vector.cons]에 지정된
default 
default 
default 

:

이 필요합니다 T는 DefaultConstructible한다.

구현시 A가 MoveConstructible 또는 CopyConstructible이라고 가정 할 수 없습니다.

+5

+1, VS쪽에 좋은 잡기. –

+0

네가 맞아, 내 다음 질문은 VC가 전혀 움직이지 않는 이유야. 할 수있는 일이 있습니까? stlport 또는 ea의 구현이 더 적합합니까? – Inverse

+0

이 std :: lib : http://libcxx.llvm.org/은 올바른 대답을 얻었지만 Windows로 이식되지 않았습니다. Windows로 이식하는 데 관심이있는 당사자와 의심의 여지없이 도움을받을 수있는 당사자가 있습니다. –

1

다음이 시도 :

std::vector<A> vec_a; 
vec_a.reserve(3); 
for (size_t i = 0; i < 3; ++i) 
    vec_a.push_back(A()); 

은 당신이 할하려는 대신 구조의 각 값에 대해 구조 + 이동을 사용하고 복사/복사/복사 초기화 프로세스를 강제합니다. 이들은 단지 다른 철학 일뿐입니다. 도서관 저자는 어느 유형에 대해 가장 좋을지 알 수 없었다.

+4

이것은 다른 철학 이상입니다. C++ 0x 초안은 올바른 동작을 지정합니다. –

+1

+1, 제안 된 코드는 실제로 해결 방법입니다. –

6

문제는 g ++의 버전에 C++ 0x 호환 라이브러리가 없다는 것입니다. 임시 후, 생성 된 일정 참조 복사에 의해 구속되고, 그 함수의 서명과 전화로

// C++ 03 
explicit vector(size_type n, const T& value = T(), 
const Allocator& = Allocator()); 

: 특히, C++ 03, 표준 : : 벡터의 크기 생성자는 다음과 같은 서명이 그것의 각 성분을 위해 창조된다.

다른 생성자가 0X ++ C에있는 동안이 경우

// C++0x 
explicit vector(size_type n); 
vector(size_type n, const T& value, const Allocator& = Allocator()); 

를 @로 (전화 첫 번째 서명과 일치하며, 요소는 컨테이너를 통해 새로운 배치로 구성 기본이어야한다 Howard Hinnant는 자신의 answer에서 컴파일러가 이동 생성자를 호출하지 말아야한다고 정확하게 지적합니다.

당신이 시도하고 표준 라이브러리를 업데이트 ++ g의 최신 버전 여부를 확인하거나, 수동 요소를 추가하여 문제를 해결할 수 있습니다 :

std::vector<A> v; 
v.reserve(3);  // avoid multiple relocations 
while (v.size() < 3) v.push_back(A()); 
1

당신은 특별한 (싼) 케이스를 추가 할 수 기본 생성 객체를 "this"객체에 복사 할 때 ctor 알고리즘을 복사하십시오. 단지 일시적인 해결책 일 뿐이지 만 그 행동은 충분히 이상합니다. 두 컴파일러 (라이브러리)는 스택에 임시 객체를 만든 다음 gcc가이 임시 객체를 대상에 3 회 복사합니다. msvc는 임시 객체를 세 번 (!) (스택에도) 다시 만들고 목표에 3 번 이동합니다. 나는 왜 그들이 장소에 직접 물건을 만들지 않는지 이해하지 못한다.

0

3 가지 변형 모두 C++ 0x 초안을 위반하지 않는다고 생각합니다. 2. T는 모든 3 변종이 기본 + 복사, 기본 + 움직임으로 동등한, 1을 만족

N

에 3. 선형 DefaultConstructible한다 1. 구축해 n 값 초기화 요소와 벡터 : 그것은 다음과 같은 요구 default 3 가지 변형 모두가 3을 만족합니다. 3 가지 변형 모두가 2를 ​​만족합니다 : DefaultConstructible 유형에서 작동합니다. 이동 가능한 유형에는 특정 알고리즘을 사용할 수 있습니다. STL에서는 기능이 다른 유형에 대해 서로 다른 버전의 알고리즘을 사용하는 것이 일반적입니다.

관련 문제