2

テンプレート化されたタイプのプレーンな古いポインターに対して、これらに代入演算子のオーバーロードがない理由はわかりません。スマートポインターを可能な限り単純な古いポインターに近づけるという目標がある場合、なぜこのような代入演算子のオーバーロードを作成しなかったのでしょうか。

inline std::shared_ptr<type> &operator=( const type * pointer)
{
    reset(a);
}

このようにして、通常のポインタと同じようにそれらを使用できます。

std::shared_ptr<int> test = new int;

それはまったく問題ではなく、なぜ彼らが数人のオペレーターに過負荷をかけるだけの問題に直面したのか疑問に思っています。

また、これを行うためにグローバル代入演算子をオーバーロードする方法があるかどうか、または私がすべきではない理由があるかどうか疑問に思っています。

編集:コードフォーマットに関するここでの彼の答えについてのNawazへの応答を追加します。私はあなたが言っていることが正しいかどうかを確認するためにこのテストプログラムを書いたばかりです:

template<class T>
class peh
{
public:
    peh() {meh = 3;}
    const peh<T> & operator=(const int * peh)
    {
    }
};

void f( peh<int> teh)
{

}

int main()
{
    int * meh = new int;

    f(meh);

    system("PAUSE");
    return 0;
}

peh<int>これは、からへの使用可能な変換がないと言ってエラーになりint *ます。では、なぜそれが受け入れstd::shared_ptr<int>られるのint *でしょうか?

4

2 に答える 2

5

また、これを行うためにグローバル代入演算子をオーバーロードする方法があるかどうか、または私がすべきではない理由があるかどうか疑問に思っています。

いいえ。代入演算子のオーバーロードは、メンバー関数である必要があります。

ちなみに、次の機能が必要な場合は、代入演算子について話すのではなく、質問する必要があります。引数として生のポインターを受け取るコンストラクターが作成されるのはなぜexplicitですか。なぜそれは暗黙的ではないのですか?

//this code requires an implicit constructor, not assignment!
std::shared_ptr<int> test = new int;  //illegal 

違法ですが、しばらくの間これが許可されたとすると、引数として生のポインタを渡して次の関数を呼び出すことができます:残りの答えが説明するように、そのような機能は危険です(コメントを読んでください) :

void f(std::shared_ptr<int> test)
{
     //code

} //test will be destructed here  (when it goes out of scope)
  //if test.use_count() == 1, then the pointer which it manages 
  //will be destructed as well. (NOTE THIS POINT)

ここで危険な部分を見てください:

int *ptr = new int;

f(ptr); 
//note that calling f is allowed if it is allowed:
//std::shared_ptr<int> test = new int;
//it is as if ptr is assigned to the parameter:
//std::shared_ptr<int> test = ptr;

//Question : now what happened in f()?
//Answer : inside f(), test (the shared_ptr) will infer that no one else
//refers to the pointer it contains, because test.use_count() == 1
//test is obviously wrong in this case, because it cannot prove that!

//DANGER
*ptr = 10; //undefined behavior, because ptr is deleted by the shared_ptr

コメントをお読みください。上記のコードスニペットの各部分について説明します。

于 2012-07-01T15:41:27.690 に答える
2

表示するものは、実際にはoperator=必要な構文を有効にしません。shared_ptr<int> p = new int;T*のshared_ptrのコンストラクターとshared_ptrのコピーコンストラクターを使用します。shared_ptrにはこれらの両方がありますが、T *のコンストラクターがであるため、構文は機能しませんexplicit

この理由は、その構築std::shared_ptr<int> test = new int;が暗黙的に実行できる場合、shared_ptrが、明示的に要求することなく、ポインターの所有権を取得できることを意味するためです。Nawazは、これが本当にエラーを起こしやすい理由の1つを示しています。使用しているポインタが、知らないうちにどこかでshared_ptrに突然採用されて、下から破壊されないように注意する必要があります。

この危険な暗黙の構造を示す例を次に示します。

#include <iostream>

template<typename T>
struct owning_pointer {
    T *t;
    owning_pointer(T *t) : t{t} {}
    ~owning_pointer() {
        std::cout << t << " deleted\n";
        delete t;
    }
};

void foo(owning_pointer<int> thief) {}

int main() {
    int *i = new int;
    std::cout << i << " allocated\n";
    foo(i);
}

出力は次のようになります。

0x10d400880 allocated
0x10d400880 deleted

explicitそして、 owning_ptrのコンストラクターに追加したときに発生するエラーを確認してください。私は得る:

main.cpp:18:5: error: no matching function for call to 'foo'
    foo(i);
    ^~~
main.cpp:13:6: note: candidate function not viable: no known conversion from 'int *' to 'owning_pointer<int>' for 1st argument;
void foo(owning_pointer<int> thief) {}
     ^

また、同じエラーの可能性なしに割り当てるための完全に単純な方法がすでにいくつかあるため、T*からの暗黙的な構築を許可する必要はありません。

std::shared_ptr<int> test(new int); // one extra character isn't a hardship. I typically prefer () construction anyway.
std::shared_ptr<int> test{new int}; // although I might start preferring {} construction in C++11
auto test = std::make_shared<int>(); // this is slightly different in that the allocated int is zero-initialized

reset()メンバーshared_ptrを初期化する場合は、代入を使用する代わりに、またはコンストラクターの本体で、初期化子リストで初期化できます。

struct foo {
    std::shared_ptr<int> m_meh;
    foo()
      : m_meh(new int)
    {
        // no need for m_meh.reset(new int) here
    }
};

これoperator=を可能にするのは次のとおりです。

shared_ptr<int> s;
s = new int;

これは、T *からのshared_ptrの暗黙的な構築ほどエラーが発生しやすいようには見えませんが、実際に価値があることもわかりません。

于 2012-07-01T16:04:04.037 に答える