web-dev-qa-db-ja.com

オブジェクトが適切に定義されていることを保証できる特性/コンセプトは何ですか?

zero_initialize()関数を定義したとしましょう:

_template<class T>
T zero_initialize()
{
    T result;
    std::memset(&result, 0, sizeof(result));
    return result;
}

// usage: auto data = zero_initialize<Data>();
_

一部のタイプでzero_initialize()を呼び出すと、未定義の動作が発生します1、2。現在、Tを確認して _std::is_pod_ を確認しています。 C++ 20で廃止されたその特性と概念の到来により、私はzero_initialize()がどのように進化するかについて興味があります。

  1. オブジェクトが適切に定義されていることを保証できる(最小の)特性/概念は何ですか?
  2. _std::uninitialized_fill_の代わりに _std::memset_ を使用する必要がありますか?なぜ?
  3. この関数は、型のサブセットのC++初期化構文の1つによって廃止されましたか?それとも、将来のC++バージョンの予定ですか?

1)クラスのすべてのメンバーを消去
2)ライブラリクラス(std :: string)でmemsetを使用すると、「未定義の動作」が発生する理由は何ですか?[終了]

21
YSC

技術的には、ユーザーコードがC++オブジェクトを合法的にmemsetできることを指定するC++のオブジェクトプロパティはありません。これにはPODが含まれるため、技術的になりたい場合は、コードが正しくありませんでした。 TriviallyCopyableでさえexistingオブジェクト間でバイト単位のコピーを実行することに関するプロパティです(中間バイトバッファーを介して)。データを発明してオブジェクトのビットに押し込むことについては何も述べていません。

つまり、あなたは合理的にである可能性がありますis_trivially_copyableandis_trivially_default_constructibleをテストすればこれが機能することを確認してください。最後の1つは重要です。これは、一部のTriviallyCopyable型がコンテンツを制御できるようにする必要があるためです。たとえば、そのような型には、常に5であるプライベートint変数があり、デフォルトのコンストラクターで初期化されます。変数にアクセスできるコードがそれを変更しない限り、それは常に5になります。C++オブジェクトモデルはこれを保証します。

したがって、そのようなオブジェクトをmemsetできなくても、オブジェクトモデルから明確な動作を得ることができます。

23
Nicol Bolas

オブジェクトの設定が適切に定義されていることを保証できる(最小限の)特性/概念は何ですか?

_std::memset_ cppreferenceの参照TriviallyCopyableタイプでのmemsetの動作は未定義。したがって、memset aTriviallyCopyableを使用しても問題ない場合は、クラスに_static_assert_を追加して、次のようなことを確認できます

_template<class T>
T zero_initialize()
{
    static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
    T result;
    std::memset(&result, 0, sizeof(result));
    return result;
}
_

ここでは _std::is_trivial_v_ を使用して、クラスが自明にコピー可能であるだけでなく、自明なデフォルトコンストラクターがあることを確認して、ゼロで初期化しても安全であることを確認します。

_std::uninitialized_fill_の代わりに_std::memset_を使用する必要がありますか?なぜ?

単一のオブジェクトを初期化するだけなので、ここで行う必要はありません。

この関数は、型のサブセットのC++初期化構文の1つによって廃止されましたか?それとも、将来のC++バージョンの予定ですか?

値またはブレース初期化は、この関数を「廃止」します。 T()および_T{}_は、初期化された値Tを提供し、Tにデフォルトのコンストラクターがない場合は、ゼロで初期化されます。つまり、関数を次のように書き直すことができます。

_template<class T>
T zero_initialize()
{
    static_assert(std::is_trivial_v<T>, "Error: T must be TriviallyCopyable");
    return {};
}
_
8
NathanOliver

zero_initializeが実際にオブジェクトをゼロ初期化することを保証する最も一般的な定義可能な特性は、

template <typename T>
struct can_zero_initialize :
    std::bool_constant<std::is_integral_v<
        std::remove_cv_t<std::remove_all_extents_t<T>>>> {};

あまり役に立ちません。ただし、標準の基本型のビット単位またはバイト単位の表現についての唯一の保証は、[basic.fundamental]/7です。「整数型の表現は、純粋なバイナリ列挙システムを使用して値を定義するものとします。」すべてのバイトがゼロの浮動小数点値がゼロ値である保証はありません。すべてのバイトがゼロのポインターまたはメンバーへのポインター値がNULLポインター値である保証はありません。 (これらはどちらも通常は実際には当てはまりますが)。

自明にコピー可能なクラス型のすべての非静的メンバーが(配列)(cv修飾)整数型である場合も、それは問題ないと思いますが、C++に反映されない限り、それをテストする方法はありません。

0
aschepler