5

この質問に答えたときに、この質問が出てきましfriend。標準は、標準ライブラリのクラスや関数を -ingすることを許可し、保証しますか?

この特定のケースでは、問題は次のような状況でした。

class MyUserDefinedType
{
    friend struct std::default_delete<MyUserDefinedType>;

private:
    ~MyUserDefinedType() { }
}

デフォルトのデリータでorオブジェクトMyUserDefinedTypeに格納できることが保証されています。std::unique_ptr<MyUserDefinedType>std::shared_ptr<MyUserDefinedType>

一般に、標準ライブラリに記述されているクラスは、その機能を直接実装する必要がありますか?それとも、任意のレベルの間接化を使用できますか? たとえば、それは可能ですか?

  • std::default_delete<MyUserDefinedType>は、実際にはusingの内部ネームスペースで定義されたクラスのエイリアスですstd。この場合、friend宣言は不正になります。

また

  • std::default_delete<MyUserDefinedType>実際に削除を行う他のクラスを呼び出します。この場合、friend宣言は目的の効果をもたらしません。

またはそれらの線に沿った何か?

私の推測では、これは動作が保証されていないUBですが、これが標準によって具体的に対処されているかどうかに興味があります。

上記の特定の例は、clang トランク (libc++ を使用) および GCC 4.7.2 (libstdc++ を使用)、FWIW で機能します。

4

2 に答える 2

5

実際にstdの内部名前空間で定義されたクラスの使用エイリアスである可能性はstd::default_delete<MyUserDefinedType>ありますか?その場合、フレンド宣言は違法になりますか?

いいえ。C++11 標準のパラグラフ 20.7.1.1.2 によると:

namespace std {
    template <class T> struct default_delete {
        constexpr default_delete() noexcept = default;
        template <class U> default_delete(const default_delete<U>&) noexcept;
        void operator()(T*) const;
    };
}

クラス テンプレートでなければならないという事実が明示的に指定されています。つまり、エイリアス テンプレートにすることはできません。だとすれば特化も無理だろう。

実際に削除を行う他のクラスを呼び出すことは可能std::default_delete<MyUserDefinedType>ですか?その場合、フレンド宣言は望ましい効果をもたらしませんか?

はい。標準には、呼び出しが一部の内部ヘルパーによって実行できないことを指定するものはありません。パラグラフ 20.1.1.2:

void operator()(T *ptr) const;

3 効果: を呼び出しdeleteますptr

4 備考:Tが不完全な型の場合、プログラムの形式が正しくありません。

これは、ファンクターで呼び出し演算子を呼び出す効果がどうあるべきかを指定するだけであり、これが具体的にどのように達成されるかを指定するものではありません (呼び出し演算子の本体内で直接、または他のクラスのメンバー関数にタスクを委譲することによって)。default_delete<>

于 2013-03-04T07:29:02.570 に答える
1

一般に、標準ライブラリに記述されているクラスは、その機能を直接実装する必要がありますか、それとも任意のレベルの間接参照を使用できますか?

一般に、実装は必要なだけ間接的に行うことができます。たとえば、標準コンテナとそのイテレータの実装を見てください。または、それらを間違って使用して、エラーメッセージからどのテンプレートが関係しているかを確認してください。ただし、これdefault_deleteは魔法ではないので、ワンライナーである必要があります。それ自体が機能することを期待できますが、保証はされません。

私の推測では、これはUBですが、これが標準によって具体的に対処されているかどうかは興味があります。

それはUBではなく、ただ不特定です。

専門化しただけであるかどうかは確かですがdefault_delete<MyUserDefinedType>(標準のlibrarayテンプレートを専門化すること許可されています)、私はそうしません。

特に、専門化されていないテンプレートに関しては、友情はまったく使用しません。このことを考慮:

//your code
class MyUserDefinedType
{
    friend struct std::default_delete<MyUserDefinedType>; //for deletion
private:  
    int veryPrivateData;
    ~MyUserDefinedType() { }
};

//evil colleague's code:
namespace std {
  //we may specialize std-templates for UDTs...
  template<>
  struct default_delete<MyUserDefinedType>
  {
    constexpr default_delete() noexcept = default;
    template <class U> default_delete(const default_delete<U>&) noexcept {}
    void operator()(T* pt) const { delete pt; }

    //sneaky...
    void access(MyUserDefinedType& mudt, int i) const
    { mudt.veryPrivateData = i; }
  };
}

void somewhere_deep_in_the_code()
{
  MyUserDefinedType& myUDT = /*something...*/;
  std::default_delete<MyUserDefinedType>().access(myUDT, 42); //tricked you!
}

友達はあなたに何でもすることができます。慎重に選択してください。この場合、カスタムデストラクタをお勧めします。デストラクタをプライベートにするのは理にかなっていると仮定しますが、デストラクタを介してアクセスを提供します。

于 2013-03-04T07:47:06.483 に答える