2

最近、私はMeyersのEffective C ++ThirdEditionを使用しています。現在取り組んでいるプロジェクトでは、コンパイラで生成された関数の使用を明示的に禁止したいクラスを作成する必要がありました。この本の項目6を参照として使用してコードを実装しましたが、私のクラスの唯一の大きな違いはテンプレート化されています。そのためのコードは次のとおりです

template <class T>
class Uncopyable
{
protected:
    Uncopyable<T>(){}
    virtual ~Uncopyable<T>(){}
private:
    Uncopyable<T>(const Uncopyable<T>&);
    Uncopyable<T>& operator=(const Uncopyable<T>&);
};

私のテスト機能。

class Test : private Uncopyable<Test>
{
public:
    Test(){}
    ~Test(){}
    inline void test()
    {
        std::cout << "blah" << std::endl;
    }
private:
protected:
};

このように使用すると、コードは期待どおりに完全に機能します

int main(int argc, char* argv[])
{
    Test t1, t2;

    // Works as expected, doesnt allow copying of object
    t2 = t1;
    // and this works fine, no copying
    Test t3 = t2;

    // finally, works correctly no copying is allowed
    Test t4(t1);

    return 0;
}

ただし、このように使用すると、コードは正常にコンパイルされ、コピーが実行されないはずのときにコピーが実行される可能性があります。

int main(int argc, char* argv[])
{
    Test* t1 = new Test(), *t2;
    t1->test();
    // Works when it shouldnt work?
    t2 = t1;
    t2->test();

    // same with this
    Test* t3 = t2;
    t3->test();

    // and this
    Test* t4(t1);
    t4->test();

    delete t1;

    return 0;
}

テンプレートクラスなしで試してみましたが、結果は同じなので、それは問題ではないと思います。

それで、なぜこれが起こるのを許されるのですか?コードにエラーがありますか、それとも概念が間違っているだけですか?ありがとう。

4

4 に答える 4

4

オブジェクトではなく、ポインタをコピーしています。これを試して:

*t2 = *t1;
于 2012-11-15T10:11:24.107 に答える
2

変更されたコードは、オブジェクト自体ではなく、ポインターをコピーしています。Test

t1、、およびすべてが同じオブジェクトを指すことにt2なり、このオブジェクトがコピーされることはありません。t3t4

于 2012-11-15T10:11:55.347 に答える
2

ここには2つの重要なことがあります。

  1. タイプとそのタイプへのポインタは、2つの非常に異なるものです。
  2. ポインタをコピーしても、ポインタが指しているものはコピーされません。

このブロックを例にとってみましょう。

Test* t1 = new Test(), *t2;
t1->test();
// Works when it shouldnt work?
t2 = t1;

t1オブジェクトはここにコピーされません。メモリ内のクラスのインスタンスは1つだけですが、現在は2つの参照があります。を呼び出すdeletet2、その単一のコピーが破棄され、他の参照t1が無効なメモリ位置を指しているようになります。

生のポインターのコピーを防ぐことができるかどうかはわかりませんが、プログラマーが簡単ににキャストし、ポインターをコピーしてTest*から、にキャストし直すことができたとしても。あらゆる種類の参照のコピーを防ぎたい場合は、スマートポインターとプライベートコンストラクターを使用する必要があります。これはまったく新しい質問です。void*Test*

于 2012-11-15T10:15:25.337 に答える
0

コンパイラーで生成された関数は、特別な関数としてC ++標準で呼び出されます。 ホエイは、特に2つの要因により呼び出されます。1。コンパイラーによって生成されます(ユーザーによって生成されない場合)。2.同じクラスの引数オブ​​ジェクトを取ります(〜destructorを除く)。


したがって、オブジェクト上のポインタの場合、そのような関数は生成されません
また、C ++ 11標準では、領域に非表示にする関数を宣言する代わりに、ステートメントprivateを使用できますdelete

于 2012-11-15T10:25:57.180 に答える