class my_class
{
...
my_class(my_class const &) = delete;
...
};
そのコンテキストで= delete
はどういう意味ですか?
他の「修飾子」(= 0
と= delete
以外)はありますか?
関数の削除は C++ 11の機能 :
「コピー禁止」の一般的なイディオムは、現在直接表現できます。
class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
[...]
「削除」メカニズムは、どの機能にも使用できます。たとえば、次のような望ましくない変換を排除できます。
struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less };
= 0
は、関数が純粋仮想であり、このクラスからオブジェクトをインスタンス化できないことを意味します。それから派生し、このメソッドを実装する必要があります= delete
は、コンパイラーがこれらのコンストラクターを生成しないことを意味します。私の知る限り、これはコピーコンストラクタと代入演算子でのみ許可されています。しかし、私は今後の標準があまり得意ではありません。The C++ Programming Language [第4版]-Bjarne Stroustrupの本からの抜粋は、=delete
を使用した本当の目的について語っています。
階層内のクラスにデフォルトのコピーまたは移動を使用するのは、通常、災害です。ベースへのポインタのみが与えられた場合、派生クラスがどのメンバーを持っているかわかりません(§3.2.2) 、したがって、それらをコピーする方法がわかりません。そのため、通常行うべき最善の方法は、デフォルトのコピーおよび移動操作を削除することです。つまり、これら2つの操作のデフォルト定義を削除することです。
class Shape { public: Shape(const Shape&) =delete; // no copy operations Shape& operator=(const Shape&) =delete; Shape(Shape&&) =delete; // no move operations Shape& operator=(Shape&&) =delete; ˜Shape(); // ... };
これで、Shapeをコピーしようとする試みがコンパイラーによってキャッチされます。
=delete
メカニズムは一般的です。つまり、任意の操作を抑制するために使用できます。
他の「修飾子」(
= 0
と= delete
以外)はありますか?
他の誰もこの質問に答えていないようですので、=default
もあることに言及する必要があります。
= delete
は、C++ 11で導入された機能です。 =delete
に従って、その関数を呼び出すことはできません。
詳細に。
クラスで考えてみましょう。
Class ABC{
Int d;
Public:
ABC& operator= (const ABC& obj) =delete
{
}
};
Obj割り当てのためにこの関数を呼び出している間は許可されません。平均値代入演算子は、あるオブジェクトから別のオブジェクトへのコピーを制限しようとしています。
私が取り組んできたコーディング標準には、ほとんどのクラス宣言について次のようなものがあります。
// coding standard: disallow when not used
T(void) = delete; // default ctor (1)
~T(void) = delete; // default dtor (2)
T(const T&) = delete; // copy ctor (3)
T(const T&&) = delete; // move ctor (4)
T& operator= (const T&) = delete; // copy assignment (5)
T& operator= (const T&&) = delete; // move assignment (6)
これらの6のいずれかを使用する場合、対応する行をコメントアウトするだけです。
例:クラスFizzBusはdtorのみを必要とするため、他の5は使用しません。
// coding standard: disallow when not used
FizzBuzz(void) = delete; // default ctor (1)
// ~FizzBuzz(void); // dtor (2)
FizzBuzz(const FizzBuzz&) = delete; // copy ctor (3)
FizzBuzz& operator= (const FizzBuzz&) = delete; // copy assig (4)
FizzBuzz(const FizzBuzz&&) = delete; // move ctor (5)
FizzBuzz& operator= (const FizzBuzz&&) = delete; // move assign (6)
ここでは1つだけコメントアウトし、他の場所(おそらくコーディング標準が示唆する場所)に実装をインストールします。他の5つ(6つ)は削除で許可されていません。
'= delete'を使用して、異なるサイズの値の暗黙的なプロモーションを禁止することもできます...例
// disallow implicit promotions
template <class T> operator T(void) = delete;
template <class T> Vuint64& operator= (const T) = delete;
template <class T> Vuint64& operator|= (const T) = delete;
template <class T> Vuint64& operator&= (const T) = delete;
新しいC++ 0x標準。 N3242 working draft のセクション8.4.3を参照してください。
(既存の回答への補遺)
...そして、削除された関数は関数の最初の宣言でなければなりません(関数テンプレートの明示的な特殊化の削除を除く-削除は特殊化の最初の宣言で行う必要があります)。つまり、関数を宣言して後で削除することはできませんその定義では、翻訳単位に対してローカルです。
削除された関数は暗黙的にインラインです。 (注:1つの定義ルール( [basic.def.odr] )は、削除された定義に適用されます。—end note]関数の削除された定義は、関数の最初の宣言、または、関数テンプレートの明示的な特殊化の場合、その特殊化の最初の宣言。[例:
struct sometype { sometype(); }; sometype::sometype() = delete; // ill-formed; not first declaration
—end example)
一般的な経験則は 関数テンプレートの特殊化を避けるため ですが、特殊化はオーバーロード解決の最初のステップに関与しないため、役に立つコンテキストがいくつかあります。例えば。 non-overloadedプライマリ関数テンプレートを使用する場合、暗黙的に変換により一致するオーバーロードに暗黙的に変換されたくないすべてのタイプに一致する定義なし;つまり、定義されていない、オーバーロードされていないプライマリ関数テンプレートの明示的な特殊化で正確な型の一致を実装するだけで、暗黙的な変換の一致の数を暗黙的に削除します。
C++ 11の削除された関数の概念の前に、単純にプライマリ関数テンプレートの定義を省略することでこれを行うことができましたが、これはあいまいなundefined referenceを与えました間違いなく、プライマリ関数テンプレートの作成者から意味的な意図をまったく与えなかったエラー(意図的に省略されていますか?)。代わりにプライマリ関数テンプレートを明示的に削除すると、適切な明示的特化が見つからない場合のエラーメッセージはより良くなり、プライマリ関数テンプレートの定義の省略/削除が意図的であることも示します。
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t);
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
//use_only_explicit_specializations(str); // undefined reference to `void use_only_explicit_specializations< ...
}
ただし、上記のプライマリ関数テンプレートの定義を単に省略せず、明示的な特殊化が一致しない場合にあいまいな未定義参照エラーが発生する代わりに、プライマリテンプレート定義を削除できます。
#include <iostream>
#include <string>
template< typename T >
void use_only_explicit_specializations(T t) = delete;
template<>
void use_only_explicit_specializations<int>(int t) {
std::cout << "int: " << t;
}
int main()
{
const int num = 42;
const std::string str = "foo";
use_only_explicit_specializations(num); // int: 42
use_only_explicit_specializations(str);
/* error: call to deleted function 'use_only_explicit_specializations'
note: candidate function [with T = std::__1::basic_string<char>] has
been explicitly deleted
void use_only_explicit_specializations(T t) = delete; */
}
より読みやすいエラーメッセージが生成され、削除の意図も明確に表示されます(undefined referenceエラーにより、開発者はこれを考えられない誤りと考える可能性があります) )。
なぜこのテクニックを使用したいのでしょうか?繰り返しますが、明示的な特殊化は、暗黙的な変換をimplicitly削除するのに役立ちます。
#include <cstdint>
#include <iostream>
void warning_at_best(int8_t num) {
std::cout << "I better use -Werror and -pedantic... " << +num << "\n";
}
template< typename T >
void only_for_signed(T t) = delete;
template<>
void only_for_signed<int8_t>(int8_t t) {
std::cout << "UB safe! 1 byte, " << +t << "\n";
}
template<>
void only_for_signed<int16_t>(int16_t t) {
std::cout << "UB safe! 2 bytes, " << +t << "\n";
}
int main()
{
const int8_t a = 42;
const uint8_t b = 255U;
const int16_t c = 255;
const float d = 200.F;
warning_at_best(a); // 42
warning_at_best(b); // implementation-defined behaviour, no diagnostic required
warning_at_best(c); // narrowing, -Wconstant-conversion warning
warning_at_best(d); // undefined behaviour!
only_for_signed(a);
only_for_signed(c);
//only_for_signed(b);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = unsigned char]
has been explicitly deleted
void only_for_signed(T t) = delete; */
//only_for_signed(d);
/* error: call to deleted function 'only_for_signed'
note: candidate function [with T = float]
has been explicitly deleted
void only_for_signed(T t) = delete; */
}
これは、継承された関数を削除できるC++ 0x標準の新しい機能です。