FILE*
次のラッパークラスを見てみましょう。
class File { FILE* handle; public: File(const char* filename) { if ( !(handle = fopen(filename, "r")) ) throw std::runtime_error("blah blah blah"); } ~File() { if (handle) fclose(handle); } // ... private: File(const File&); // void operator=(const File&); // };
FILE*
コピーにはプラットフォーム固有のトリックが必要であり、通常は物理的な意味があまりないため、このクラスのオブジェクトのコピーおよび割り当てを禁止します。
File
型のオブジェクトのリスト全体を保存する場合はどうしますか? 残念ながら、標準コンテナで
File
を使用することはできません。つまり、このようなコードは単にコンパイルされません。
std::vector<File> files; files.push_back(File("data.txt"));
C ++ 98でのこの問題の一般的な解決策は、
shared_ptr
を使用することです。
std::vector<boost::shared_ptr<File> > files; files.push_back(boost::shared_ptr<File>(new File("data.txt")) );
このソリューションは、特に必要ではないと思われる動的メモリを使用するという事実を考慮すると、目には特に喜ばしいものではありません。
C ++ 11の使用を許可すると、状況は大きく変わります。 移動セマンティクスの出現により、標準コンテナでは、コンテナ全体をコピーする場合を除き、通常のコピーコンストラクタと代入演算子は不要になりました。 代わりに、ディスプレイスメントのセマンティクスで十分です。 C ++ 11の
File
クラスを使用して例を書き換える方法を見てみましょう。
class File { FILE* handle; public: File(const char* filename) { if ( !(handle = fopen(filename, "r")) ) throw std::runtime_error("blah blah blah"); } ~File() { if (handle) fclose(handle); } File(File&& that) { handle = that.handle; that.handle = nullptr; } File& operator=(File&& that) { std::swap(handle, that.handle); return *this; } File(const File&) = delete; // void operator=(const File&) = delete; // // ... };
繰り返しますが、通常のコピーは禁止しますが、オブジェクトの移動は許可します。 これでこのコードは機能します:
std::vector<File> files; files.push_back(File("data1.txt")); files.push_back(File("data2.txt")); files.erase(files.begin());
さらに、可変テンプレートのおかげで、新しいテンプレート関数
emplace_back
コンテナに登場しました。これにより、オブジェクトをコピーせずにコンテナ内に直接作成できます。
std::vector<File> files; files.emplace_back("data1.txt"); // File("data1.txt")
このノートが、イノベーションが移動オブジェクトのセマンティクスであることの重要性を明確に示していることを願っています。 新しい標準への移行におけるすべての成功!