2014-08-29 4 views
19

임시가 생성자의 이니셜 라이저 목록에있는 참조 멤버에 바인딩되어 있으면 생성자가 반환 할 때 개체가 파괴된다는 것을 알고 있습니다. 생성자에서 참조 멤버에 임시 바인딩에 대한 가짜 경고

그러나, 다음 코드를 고려하십시오

#include <functional> 
#include <iostream> 

using callback_func = std::function<int(void)>; 

int 
func(const callback_func& callback) 
{ 
    struct wrapper 
    { 
    const callback_func& w_cb; 
    wrapper(const callback_func& cb) : w_cb {cb} { } 
    int call() { return this->w_cb() + this->w_cb(); } 
    }; 
    wrapper wrp {callback}; 
    return wrp.call(); 
} 

int 
main() 
{ 
    std::cout << func([](){ return 21; }) << std::endl; 
    return 0; 
} 

이 나에게 완벽하게 유효한 보인다. callback 개체는 func 함수의 전체 실행 중에 작동하며 wrapper의 생성자에 대한 임시 복사본을 만들지 않아야합니다.

실제로, GCC 4.9.0은 모든 경고가 활성화 된 상태에서 정상적으로 컴파일됩니다.

$ g++ -std=c++11 -W main.cpp 
main.cpp: In constructor ‘func(const callback_func&)::wrapper::wrapper(const callback_func&)’: 
main.cpp:12:48: warning: a temporary bound to ‘func(const callback_func&)::wrapper::w_cb’ only persists until the constructor exits [-Wextra] 
    wrapper(const callback_func& cb) : w_cb {cb} { } 
              ^

이 거짓 긍정적인가, 아니면 내가 개체의 수명을 오해하고 있습니다 :

그러나 GCC 4.8.2 컴파일러는 나에게 다음과 같은 경고 준다? 여기

내 정확한 컴파일러 버전 테스트 :

$ g++ --version 
g++ (GCC) 4.8.2 
Copyright (C) 2013 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
$ g++ --version 
g++ (GCC) 4.9.0 20140604 (prerelease) 
Copyright (C) 2014 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
+0

최적화를 해제하면 오류가 발생합니다. Valgrind는 문제가'func (std :: function const &) :: wrapper :: call()'어딘가에 있다고 지적합니다. –

+2

'w_cb {cb}'를 사용하면 세분화 위반이 발생합니다. 'w_cb (cb)'를 사용하면 같은 문제가 발생하지 않습니다. g ++ 4.8.3에서 테스트되었습니다. –

+0

GCC 4.8.2에서 Valgrind 오류를 재현 할 수있었습니다. GCC 4.9.0에 의해 생성 된 실행 파일은 Valgrind-clean입니다. (세그 폴트, 터프가 아니라, 프로그램이 42를 출력하고 예상대로 성공적으로 종료됩니다.) 이러한 관찰은 최적화 수준에 따라 달라지지 않습니다. – 5gon12eder

답변

12

이 4.9에서 수정되었습니다 GCC 4.8의 버그입니다. 여기에 버그 리포트입니다 :; 토니 D 덕분에

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50025

+1

버그가 * warning *이 아니라 * 경고 *가 경고한다는 사실이 유용 할 것입니다. 나는 링크에 가야만 ... 즉, 일시적으로 실제로 gcc 4.8에서 생성되었고 오래 지속될 수 없다는 것을 결정해야했습니다. 최적화를 통해 임시가 사라지게 할 수 있습니까? – Yakk

+0

예, 무슨 일이 일어나고 있는지 설명합니다. 링크를 가져 주셔서 감사합니다. 나는 그것에 의해 영감을 얻은 몇 가지 추가 연구를했고 대답으로 게시 할 것이지만 나는 당신을 받아 들일 것입니다. – 5gon12eder

+4

이것은 표준의 버그 였고 GCC는 표준의 정확한 표현을 구현하고있었습니다. DR 1288이 표준을 수정했습니다. –

5

로는 하워드 Hinnant 지적 이미 R Sahu의 의견에 의해 표시는,이 당시 깨진 표준에서 요구하는 데 사용 버그 (이다 이것을 가리 키기 위해) GCC 4.8이 초기화리스트를 다루는 방식에서.

wrapper(const callback_func& cb) : w_cb (cb) { } 

wrapper(const callback_func& cb) : w_cb {cb} { } 

에서 내 원래의 예에서 생성자를 변경하면 GCC 4.8.3와 경고가 사라와 생성 된 실행 Valgrind의 깨끗한 있습니다. 두 어셈블리 파일의 diff는 너무 커서 여기에 게시하지 않습니다. GCC 4.9.0은 두 버전 모두에 대해 동일한 어셈블리 코드를 생성합니다.

다음으로 나는 std::function을 사용자 정의 구조체 및 삭제 된 복사 및 이동 생성자 및 할당 연산자로 바꿨습니다. 실제로 GCC 4.8.3에서는 경고가 유지되지만 위의 코드 행에서 구조체의 삭제 된 복사본 생성자를 호출하는 오류 (약간 더 도움이 됨)가 제공됩니다. 예상대로 GCC 4.9.0과 차이는 없습니다.