2

更新:回避策にAutoAを使用するようにコード例を編集しました(これは当初の意図でした)。rlbondの答えを見てこれを実現しました。

auto_ptrこのスレッドからの推奨事項に基づいて、コードにの使用法を取り入れようとしています。

メソッドインターフェイスを介してC++引数の使用法を表現する

ただし、Visual Studio 6.0でコンパイルすると、予期しないコンパイルエラーが発生します。std::auto_ptr派生型のaからstd::auto_ptr基本型のへの割り当て/コピーを処理するときに問題があります。これは私のコンパイラに固有の問題ですか?

Boostを使用することを強くお勧めしますが、私のプロジェクトではそれはオプションではありません。それでも使用したい場合はauto_ptr、呼び出しの回避策を使用する必要がありstd::auto_ptr::release()ますか?私がこれまでに遭遇したことから、この問題はコンパイラエラーを引き起こすので、簡単に見つけることができます。ただし、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

3 に答える 3

5

最初のものは簡単です:

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

これは、 VC6の標準ライブラリがサポートしていないメンバー関数テンプレートを必要とするため、VC6では失敗します。ただし、標準に準拠したコンパイラでコンパイルされます。

回避策:

AutoA b_auto_to_a_auto( b_auto.release() );

2つ目ははるかに微妙です:)

sink(b_raw_to_b_auto);  //fails to compile

暗黙の変換が行われているため、これは標準に準拠したコンパイラでコンパイルしないでください。コンパイラは上記を次のように変換します

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

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

そこに行きます-コンパイルエラー。AFAICSこれは標準に準拠した動作です。std::auto_ptrC ++-0xの「移動セマンティクス」は、右辺値参照を取得する「コピーコンストラクター」を追加することでこれを修正しますが、将来どのくらいの愛がまだ受けられるかはわかりませんstd::shared_ptr

2番目の回避策:

AutoA tmp( b_raw_to_b_auto/*.release() for VC6*/ );
sink( tmp );
于 2009-07-17T04:26:44.683 に答える
4
AutoA b_auto_to_a_auto(b_auto);  //fails to compile

sink(b_raw_to_b_auto);  //fails to compile

Pavel Minaevは、私が実際に知らなかったことを指摘しています。

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

sink(static_cast<AutoA>(b_raw_to_b_auto));

VC6は、テンプレートがあまり得意ではないことで有名です。

コードベースを実際に機能するものにアップグレードし、特にRAIIテクニックの使用を開始することを強くお勧めしますboost::shared_ptr。私はあなたができないと言っていることを知っています、そして私はそれが難しいことを知っています、しかしあなたは事実上メモリリークがなく、そして多くの、はるかに少ないバグがあります。

繰り返しになりますが、完全な機能がなくても使用できますauto_ptrか?

于 2009-07-17T00:59:01.087 に答える
2

ここには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ください。そして、規格はさらに次のように述べています。

必要条件:Y*は暗黙的にX*に変換できます。

ここで注意する必要があるのは、コンストラクター引数が非定数への参照であるということだけです。あなたの場合、これは問題ではありませんが(const以外の変数を渡すため)、次の部分で重要になります。ここで結論を出すと、あなたが見ているのは、VC6の非標準的な動作です。準拠したコンパイラでコンパイルする必要があります(VC7以降でコンパイルされます)。次に、2番目のことです。

sink(b_raw_to_b_auto);  //fails to compile

これは実際にはmmutzによって完全に説明されているので、ここでは詳しく説明しません。彼の回答を参照してください。結論として:はい、この行はコンパイルされるべきではなく、準拠したコンパイラー(またはあなたが知っているようにVC6)ではありません。

于 2009-07-17T04:50:50.733 に答える