2009-07-17 2 views
2

업데이트 : 해결 방법으로 AutoA를 사용하는 편집 된 코드 예제 (원래의 의도 임). rlbond의 대답을보고 나서 이것을 깨달았습니다. std :: auto_ptr Visual Studio 6.0의 컴파일 문제

나는이 스레드의 추천에 따라 내 코드에 auto_ptr의 사용을 통합하기 위해 노력하고 있어요 :

Express the usage of C++ arguments through method interfaces

을 그러나, 나는 비주얼 스튜디오 6.0로 컴파일 할 때 예기치 않은 오류가 컴파일 수신하고 있습니다. 파생 형식의 std::auto_ptr의 할당/복사본을 기본 형식 인 std::auto_ptr에 적용 할 때 문제가 있습니다. 이 문제는 제 컴파일러에 관련된 것입니까?

부스트를 사용하는 것이 좋습니다.하지만 내 프로젝트에서는 옵션이 아닙니다. auto_ptr을 계속 사용하려면 std::auto_ptr::release()으로 전화를 걸어 해결 방법을 사용해야합니까? 지금까지 내가 겪은 것으로부터이 문제는 컴파일러 오류가 발생하므로 쉽게 잡을 수 있습니다. 그러나 기본 형식의 'auto_ptr'에 할당하기 위해 릴리스를 호출하는 컨벤션을 채택하여 유지 관리 문제에 대해 알려줄 수 있습니까? 특히 다른 컴파일러로 빌드 된 경우 (다른 컴파일러에는이 문제가 없다고 가정).

내 상황으로 인해 release() 해결 방법이 좋지 않은 경우 소유권 이전을 설명하기 위해 다른 규칙을 사용하여 대체해야합니까?

다음은 문제를 설명하는 예입니다.

#include "stdafx.h" 
#include <memory> 

struct A 
{ 
    int x; 
}; 

struct B : public A 
{ 
    int y; 
}; 

typedef std::auto_ptr<A> AutoA; 
typedef std::auto_ptr<B> AutoB; 

void sink(AutoA a) 
{ 
    //Some Code.... 
} 

int main(int argc, char* argv[]) 
{ 
    //Raws to auto ptr 
    AutoA a_raw_to_a_auto(new A()); 
    AutoB b_raw_to_b_auto(new B()); 
    AutoA b_raw_to_a_auto(new B()); 

    //autos to same type autos 
    AutoA a_auto_to_a_auto(a_raw_to_a_auto); 
    AutoB b_auto_to_b_auto(b_raw_to_b_auto); 

    //raw derive to auto base 
    AutoB b_auto(new B()); 

    //auto derive to auto base 
    AutoA b_auto_to_a_auto(b_auto); //fails to compile 

    //workaround to avoid compile error. 
    AutoB b_workaround(new B()); 
    AutoA b_auto_to_a_auto_workaround(b_workaround.release()); 

    sink(a_raw_to_a_auto); 
    sink(b_raw_to_b_auto); //fails to compile 

    return 0; 
} 

컴파일 오류 :

Compiling... 
Sandbox.cpp 
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(40) : error C2664: '__thiscall std::auto_ptr<struct A>::std::auto_ptr<struct A>(struct A *)' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'struct A *' 
     No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(47) : error C2664: 'sink' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'class std::auto_ptr<struct A>' 
     No constructor could take the source type, or constructor overload resolution was ambiguous 
Error executing cl.exe. 

Sandbox.exe - 2 error(s), 0 warning(s) 
+4

심각하게? 11 년 된 컴파일러? 사람들이 계속 나아갈 것 같아. – shoosh

+0

이동할 곳이있을 것이라고 생각할 것입니다. 10은 새로운 6이지만 10은 여전히 ​​베타 버전입니다. –

답변

5

첫 번째는 간단합니다 : 그것은 멤버 함수 템플릿을 요구하기 때문에이 VC6에 실패

AutoA b_auto_to_a_auto(b_auto); //fails to compile 

, 뭔가 VC6의 표준 라이브러리는 지원하지 않습니다. 표준 호환 컴파일러에서 컴파일됩니다.

해결 방법 :

AutoA b_auto_to_a_auto(b_auto.release()); 

두 번째는 훨씬 더 미묘하다 :

sink(b_raw_to_b_auto); //fails to compile 

이 하나가 표준을 준수하는 컴파일러에서 컴파일되지해야한다, 무슨 암시 적 변환이 있기 때문에. 컴파일러 sink 의해 std::auto_ptr<A>소요되므로 컴파일러에 의해 암시 적으로 생성 된 임시 std::auto_ptr<A>가 될 필요

sink(std::auto_ptr<A>(b_raw_to_b_auto)); 

단에 상기 변 복사본 구성 sink의 인수로. 자, 임시 보관 인은 의 직위 인입니다. Rvalues는 const가 아닌 참조에 바인딩되지 않지만 std::auto_ptr의 "복사 생성자"는 이 아닌 const 참조로 인수를 취합니다.

오류가 발생했습니다. AFAICS 이것은 표준을 따르는 행동입니다. 0x38 "move semantics"는 rvalue 참조를 취하는 "복사 생성자"를 추가함으로써 해결할 것입니다. std::auto_ptr이 앞으로도 얼마나 많은 사랑을 받을지 확신하지는 않지만 std::shared_ptr과 함께 무엇을 할 것입니까? 두 번째에 대한

해결 방법 :

AutoA tmp(b_raw_to_b_auto/*.release() for VC6*/); 
sink(tmp); 
+0

답해 주셔서 감사합니다. VC6의 템플릿과 관련이 있다는 느낌이 들었습니다. 전에 문제가있었습니다. 나는 그것이 왜 VC6에 문제가되는지를 예상했는데, 이유를 찾아내는 것이 흥미 롭습니다. 그 rvalues ​​세부 사항에 대해 알지 못했습니다. 좋은 정보입니다. 집에 돌아온 후에, 나는 당신이 말한 것과 일치하는 빌드 결과를 표준에 맞출 수있었습니다. 답장을 보내 주셔서 감사합니다. –

4
AutoA b_auto_to_a_auto(b_auto); //fails to compile 

sink(b_raw_to_b_auto); //fails to compile 

파벨 Minaev가 실제로 모르는 뭔가 지적하십시오에서 암시 적 변환이 있기 때문에,

첫 번째 호출은 컴파일해야한다을 B *에서 A *로. 그러나 두 번째 컴파일되지 않습니다. 다음은 수행 할 것입니다 :

sink(static_cast<AutoA>(b_raw_to_b_auto)); 

VC6은 템플릿이 좋지 않은 것으로 유명합니다.

코드베이스를 실제로 작동하고 RAII 기술을 사용하기 시작한 코드베이스, 특히 boost::shared_ptr으로 업그레이드하는 것이 좋습니다. 나는 당신이 할 수 없다고 말하고, 그것이 어렵다는 것을 안다. 그러나 당신은 사실상 메모리 누수가 없으며 버그는 더 적고 많지 않다.

그런 다음 다시 전체 기능이 없어도 auto_ptr을 사용할 수 있습니까?

+0

auto_ptr에 대한 내 이해는 일반적인 포인터와 비슷한 의미를 갖기위한 것입니다.예를 들어, 내가 함수를 가지고 있다면 void sink (A * a); 다음과 같이 전화를 걸 수 있습니다. B * b = new B(); 싱크대 (b); std :: auto_ptr을 사용할 때 피할 수없는 한계점이라면, 내가하려고하는 것 또는 내 접근법에 대한 유용성을 재고해야합니다. 싱크 (sink)에 대한 귀하의 의견은 실제로 auto_ptr로 전달 된 객체의 소유권을 이전하려고 할 때 원하는 경우입니다. –

+0

내가 말하고있는 것은 정확히 하나의 auto_ptr이 하나의 객체를 소유 할 수 있으며 할당 또는 복사가 소유권을 이전한다는 것입니다. 많은 사람들이 auto_ptr이 나쁜 디자인이라고 믿습니다. 예를 들어 auto_ptr은 STL 컨테이너에서 사용할 수 없습니다. 당신이하는 일을 잘 알고 있다면 괜찮습니다.하지만 할당은 일반적인 포인터처럼 작동하지 않습니다. 부스트가 옵션이 아니라는 것을 알고 있지만 boost의 shared_ptr은 공유 소유권이 필요한 경우 정말로 원하는 것입니다. – rlbond

+0

"A와 B가 관련되어 있어도 관계가없는 유형입니다." 및 "A와 B를 다형 적으로 처리하려면 auto_ptr 을 사용하십시오." 이것을 기반으로 boost :: shared_ptr에 같은 문제가 있다고 가정하겠습니다. –

2

여기에 두 가지 문제가 있습니다. , 우선이 :

AutoA b_auto_to_a_auto(b_auto); 

완벽하게 표준을 준수하고 컴파일해야한다. 이유를 설명해 드리겠습니다. ISO C++ 표준은 (20.4.5.1 [lib.auto.ptr.cons]/4-6) auto_ptr<X> (다른 것들 중에서)에 대한 다음 생성자를 지정합니다. Y 여기 X에서 다른 유형인지

template<class Y> auto_ptr(auto_ptr<Y>&) throw(); 

참고. 그리고 표준은 또한 말한다 : 여기에주의를 지불하는

Requires: Y* can be implicitly converted to X*.

있는 유일한 방법은 생성자 인수가 참조 - 투 - const가 아닌입니다. 귀하의 경우, 이것은 문제가되지 않습니다 (거기에 비 const 변수를 전달하기 때문에), 다음 부분에서는 중요 해집니다. 여기서 결론을 맺으십시오 : VC6에서 비표준 동작이 표시됩니다. 그것은 호환 컴파일러에서 컴파일해야합니다 (그리고 VC7 이상에서 컴파일됩니다). 이제 두 번째 것 :

sink(b_raw_to_b_auto); //fails to compile 

이 것은 실제로 완벽하게 mmutz에 의해 설명되었으므로 여기서 자세히 설명하지 않겠습니다 - 그의 대답을보십시오. 결론을 내리면 : 예,이 라인은 컴파일되어서는 안되며, 호환 컴파일러 (또는 VC6, 당신이 알아 낸 것)에 없을 것입니다.