2015-01-28 2 views
13

다음 코드를 고려하시기 바랍니다. 다음 코드와 실패,다른 동작은

int main() { 
    A arr[2] = {{"a"}, {"b"}}; 
    return 0; 
} 

:하지만 g ++ (4.9.1)이 성공적으로 다음 코드를 만들 수,

class Aggr { 
private: 
    A arr[2]; 
public: 
    Aggr() : arr{{"a"}, {"b"}} {} 
}; 

오류 메시지가

test.cc: In constructor ‘Aggr::Aggr()’: 
test.cc:22:28: error: use of deleted function ‘A::A(A&&)’ 
    Aggr() : arr{{"a"}, {"b"}} {} 
          ^   
test.cc:11:3: note: declared here 
    A(A&&) = delete; 
^

는 말했다 list-initializer는 클래스 내부의 배열을 초기화하기 위해 이동 생성자를 호출하려고 시도합니다. 그러나이 코드는 경고없이 clang v3.5에 의해 성공적으로 빌드되었습니다. 그래서, 나는 C++ 11 (또는 이후 버전) 목록 - 초기화에 대한 규칙을 지정 무엇인지 알고 싶습니다. 미리 감사드립니다.

+0

왜 'A &&'입니까? – ZivS

+0

@ZivS 참조 번호 – bolov

+3

가능성이있는 문제 : http://stackoverflow.com/questions/26685551/how-to-initialize-array-of-classes-with-deleted-copy-constructor-c11 – marcinj

답변

2

또 다시 표준을 읽고, 나는 이것이 버그라고 생각합니다.

표준은 무엇을 말하는가 ?

8.5.1/2

: 응집체가 초기화리스트 초기화되면 8.5.4에 명시된 바와 같이, 초기화리스트의 요소의 집합체의 구성원 이니셜로 찍은, 에 첨자 또는 회원 주문 증가. 각각의 부재는 대응 초기화 절에서 초기화 카피.

이 설명된다 :

8.5/14 : (...) 사본 초기화라고합니다. [주 : 복사 초기화는 동작을 호출 할 수 있습니다 (12.8). -end note]

그러나 12.8에는 특정 경우에 이동이 필요할 것이라는 증거가 없습니다.

8.5.4/3 그렇지 않으면 T가 클래스 유형 인 경우 생성자가 고려됩니다. T가 이니셜 라이저 -리스트 생성자를 가지면, 인수 은 이니셜 라이저 목록을 단일 인수로 구성한다; 그렇지 않으면 인수 목록은 이니셜 라이저 목록의 요소로 구성됩니다. 적용 가능한 생성자가 열거되고 가장 좋은 것이 과부하 해결 (13.3)을 통해 으로 선택됩니다. 원칙적 그래서

당신이 코드는 작동합니다!

는 버그인가? 실험적인 방법 시도하기

암시 적 이동 생성자의 이점을 얻기 위해 이동 생성자의 삭제를 주석 처리했습니다.이상하게도 다음과 같은 오류 메시지가 나타납니다.

Compilation error time: 0 memory: 3232 signal:0 

prog.cpp: In constructor 'Aggr::Aggr()': 
prog.cpp:19:28: error: use of deleted function 'A::A(const A&)' 
    Aggr() : arr{{"a"}, {"b"}} {} 
          ^
prog.cpp:10:3: note: declared here 
    A(const A&) = delete 

이제 그는 누락 된 복사본 생성자에 대해 불평합니다!

더 이상하게도, 나는 암시 적 하나 대신에 내 자신의 이동 생성자를 제공했다. 여기서 코드를 성공적으로 컴파일했다 !!

마지막 I는 복사 및 이동을 모두 구비하고 일부 추적 덧붙여

class A { 
private: 
    std::string s; 
public: 
    A() = delete; 
    A(const A&) { std::cout<<"copy\n";} //= delete; 
    A(A&&) { std::cout<<"move\n";} //= delete; 
    A(const std::string &a) : s(a) { std::cout<<"string ctor\n";} 
}; 

및 I는 Aggr 객체를 생성 할 때, 단지 표시

string ctor 
string ctor 

배열 부재 인 것을 도시 우리가 예상했던대로 복사 elision을 사용하여 문자열 생성자를 초기화합니다.

이러한 모든 테스트는 ideonone에서 gcc-9.4.2를 사용하여 C++ 14 옵션으로 수행되었습니다.

결론

같은 코드가 암시 적 이동의 ctor와 함께 컴파일에 실패하고 사용자 정의 이동의 ctor 버그처럼 매우 심각하게 보이는으로 성공한다는 사실.

이동 생성자가 사용 가능한 경우 사용되지 않는다는 사실은이 인상을 강화합니다.

결과적으로 this bug을 신고했습니다.

+0

좋은 답변 및이 버그를 신고 해 주셔서 감사합니다. – Destructor