class my_class
{
...
my_class(my_class const &) = delete;
...
};
= delete
その文脈ではどういう意味ですか?
他の「修飾子」(= 0
および以外= delete
)はありますか?
#define
0に評価され、それから隠し関数か何かを宣言するla Qtだと思っていました。
class my_class
{
...
my_class(my_class const &) = delete;
...
};
= delete
その文脈ではどういう意味ですか?
他の「修飾子」(= 0
および以外= delete
)はありますか?
#define
0に評価され、それから隠し関数か何かを宣言するla Qtだと思っていました。
回答:
関数の削除は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 };
=delete
すると、メソッドを見ることができるコンテキストprivate
(つまり、クラスとそのフレンド内)からでもメソッドにアクセスできなくなります。これにより、コードを読んでいるときの不確実性がなくなります。@Prasoon、その2番目の例は、まだコンストラクターを削除しているだけです- operator long ()
たとえば、削除されたものを見るとよいでしょう。
= delete
良く使うよりprivate
通常あなたがいるためか、他の類似のメカニズムたい禁断の機能が目に見えて宣言され、オーバーロードの解決などのために検討することが可能な限り早期に失敗し、ユーザーに明確なエラーを提供できるように、。宣言を「隠す」ことを含むソリューションは、この影響を減らします。
= 0
関数が純粋な仮想であり、このクラスからオブジェクトをインスタンス化できないことを意味します。あなたはそれから派生し、このメソッドを実装する必要があります= delete
コンパイラーがそれらのコンストラクターを生成しないことを意味します。私の知る限り、これはコピーコンストラクタと代入演算子でのみ許可されています。しかし、私は次の標準にはあまり上手ではありません。=delete
構文には他にもいくつかの使い方があります。たとえば、これを使用して、呼び出しで発生する可能性のあるある種の暗黙的な変換を明示的に禁止できます。このためには、オーバーロードされた関数を削除するだけです。詳細については、C ++ 0xのWikipediaページをご覧ください。
= delete
は完全に正確ではありません。= delete
どの関数にも使用できます。その場合、削除済みとして明示的にマークされ、使用するとコンパイラエラーが発生します。特別なメンバー関数の場合、これは特に、コンパイラーによって生成されないことも意味しますが、これは削除された結果であり、= delete
実際の結果ではありません。
このC ++プログラミング言語[第4版]からの抜粋-Bjarne Stroustrupの本は、使用の背後にある真の目的について述べてい=delete
ます。
3.3.4操作の抑制
階層内のクラスにデフォルトのコピーまたは移動を使用することは、通常、惨事です。ベースへのポインターしか与えられていないので、派生クラスのメンバーがわからないので、それらをコピーする方法がわかりません。したがって、通常は、デフォルトのコピーおよび移動操作を削除すること、つまり、これら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
ます。
私が使用したコーディング標準には、ほとんどのクラス宣言について次のものが含まれています。
// 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ワーキングドラフトのセクション8.4.3を参照してください
(既存の回答の補遺)
...そして、削除された関数は関数の最初の宣言でなければなりません(関数テンプレートの明示的な特殊化を削除する場合を除いて-削除は特殊化の最初の宣言にある必要があります)。つまり、関数を宣言して後で削除することはできません。翻訳単位に対してローカルな定義で。
削除された関数は暗黙的にインライン化されます。(注:削除された定義には、1つの定義ルール([basic.def.odr])が適用されます。— 末尾の注 ]関数の削除された定義は、関数の最初の宣言、または関数テンプレートの明示的な特殊化、その特殊化の最初の宣言[例:
struct sometype { sometype(); }; sometype::sometype() = delete; // ill-formed; not first declaration
— 例を終了)
特殊化はオーバーロード解決の最初のステップに参加しないため、一般的な経験則は関数テンプレートの特殊化を避けることですが、それが役立つコンテキストがいくつかあります。たとえば、定義のないオーバーロードされていないプライマリ関数テンプレートを使用して、暗黙的に変換によるマッチングによるオーバーロードに暗黙的に変換したくないすべてのタイプに一致させる場合。つまり、定義されていない、オーバーロードされていないプライマリ関数テンプレートの明示的な特殊化で、型の完全一致を実装するだけで、暗黙的な変換の一致の数を暗黙的に削除します。
C ++ 11の削除された関数の概念の前に、1次関数テンプレートの定義を単に省略することでこれを行うことができましたが、これにより、1次関数テンプレートの作成者から意味的な意図がまったくないと思われる曖昧な未定義の参照エラーが発生しました(意図的に省略) ?)。代わりに一次関数テンプレートを明示的に削除すると、適切な明示的な特殊化が見つからない場合のエラーメッセージがより良くなり、一次関数テンプレートの定義の省略/削除が意図的なものであったことも示されます。
#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; */
}
削除の意図も明確に表示される、より読みやすいエラーメッセージを生成します(未定義の参照エラーにより、開発者はこれを思いがけない間違いと考える可能性があります)。
なぜ私たちがこのテクニックを使いたいのでしょうか?この場合も、明示的な特殊化は、暗黙的な変換を暗黙的に削除するのに役立ちます。
#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標準の新しい機能です。
void foo(int); template <class T> void foo(T) = delete;
すべての暗黙の変換を停止します。int
タイプの引数のみが受け入れられ、他のすべての引数は「削除された」関数をインスタンス化しようとします。