2009-07-17 16 views
2

更新:回避策(元の意図)にAutoAを使用するコード例を編集しました。 rlbondの答えを見て、これを実現しました。std :: auto_ptr Visual Studio 6.0でのコンパイルの問題

は、私はこのスレッドからの勧告に基づいて、私のコードでauto_ptrの使用を組み込むしようとしています:のVisual Studio 6.0でコンパイルするとき

Express the usage of C++ arguments through method interfaces

しかし、私はいくつかの予期しないコンパイルエラーを受け付けております。派生型のstd::auto_ptrの代入/コピーを基底型のstd::auto_ptrに処理するときに問題があります。これは私のコンパイラ特有の問題ですか?

Boostを使用することを強くお勧めしますが、私のプロジェクトではオプションではありません。 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 

起こって暗黙の変換がありますので、この1つは、標準準拠のコンパイラでコンパイルべきではありません。コンパイラは、上記

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

に変身しかし、sinkstd::auto_ptr<A>を取るので、コンパイラによって暗黙的に作成された一時std::auto_ptr<A>sinkの引数にコピー構築する必要があります。今のような一時的なものはの値です。 Rvaluesは非const参照にバインドしませんが、std::auto_ptrの "コピーコンストラクター"は非const参照の引数をとります。

エラーが表示されます。 AFAICSこれは標準に準拠した動作です。 C++ - 0x "move semantics"は、r値の参照を取る "コピーコンストラクタ"を追加することで修正されますが、std::auto_ptrがまだどれくらいの愛をまだ受け取るかわからないのですが、std::shared_ptrとは何ですか? 1秒間

回避策:

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

答えをありがとう。私はそれがVC6のテンプレートと関係していたと感じていました。私はこれまでに問題がありました。私はそれがなぜVC6に問題があると思っていたのでしょうか、興味がない理由を見つけるのは面白いです。私はその弁護士の詳細について知りませんでした、それは知っている良い情報です。家に帰ってからは、あなたが言うことに一致するビルド結果を標準に準拠させることができました。あなたの返事のために他の人に感謝します。 –

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

sink(b_raw_to_b_auto); //fails to compile 

パベルMinaevは私が実際に知らなかった何かを指摘する:からの暗黙の型変換があるため、

最初の呼び出しはコンパイルする必要がありますがB *をA *に変換する。 しかし、2番目はコンパイルされません。次のようになります:

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を使用しているときに回避できない制限がある場合は、私がやろうとしていることや自分のアプローチについて有用であると再考する必要があります。 auto_ptrで渡されたオブジェクトの所有権を譲り渡そうとしているので、シンクに対するあなたのコメントは、私の場合、実際には望ましい動作です。 –

+0

私が言っているのは、ちょうど1つのauto_ptrが1つのオブジェクトを所有することができ、その割り当てまたはコピーが所有権を移譲するということです。多くの人々はauto_ptrがこれのために悪い設計であると信じています。たとえば、auto_ptrはSTLコンテナでは使用できません。 あなたが何をしているか分かっている限り、大丈夫ですが、割り当ては通常のポインタのようには機能しません。ブーストはオプションではないと私は知っていますが、共有の所有権が必要な場合はboost_subt_preは本当に必要なものです。 – 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>のための次のコンストラクタを指定します。

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

YがここXは異なるタイプであることに注意してください。標準はさらにこう述べています。ここに注意を払うために

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

唯一のものは、コンストラクタの引数は、参照・ツー・非constであるということです。あなたのケースでは、これは問題ではありません(そこに非const変数を渡しているので)、次の部分では重要になります。 VC6のの非標準動作が表示されます。 は、対応するコンパイラでコンパイルする必要があります(VC7以上でコンパイルされます)。今すぐ上の第二のものへ:

sink(b_raw_to_b_auto); //fails to compile 

この1つは実際には完全にmmutzによって説明されたので、私はここでは詳細には触れません - 彼の答えを参照してください。結論としては:はい、この行はコンパイルしてはならず、準拠したコンパイラ(またはVC6、あなたが見つけたように)にはありません。

関連する問題