关于C++ Implicitly-declared move assignment operator规则的技术咨询
Alright, let's unpack this cppreference rule step by step—this is all about when the C++ compiler automatically creates a move assignment operator (that’s the T& operator=(T&&) function) for your class, struct, or union, no code from you required. Let’s break down every part clearly.
The Hard Requirements (All Must Be Met)
For the compiler to generate this implicit move assignment operator, every single one of these conditions has to be true:
- No user-declared copy constructors: If you wrote any version of
T(const T&)(even an empty placeholder), the compiler won’t auto-generate the move assignment. - No user-declared move constructors: Same logic—if you defined
T(T&&)yourself, the compiler assumes you’re handling move logic manually and stays out of the way. - No user-declared copy assignment operators: Any custom
T& operator=(const T&)you wrote kills the implicit move assignment generation. - No user-declared destructors: If you have a custom
~T(), the compiler figures you’re managing resources (like memory or file handles) and won’t auto-generate a move assignment that might mess with your cleanup logic.
The C++14 Pre-Condition
Before C++14, there’s an extra check: the implicitly-declared move assignment operator can’t be deleted. What triggers that? A few common cases:
- One of your class’s members can’t be move-assigned (e.g., a member with a deleted move assignment operator, or a
constmember that can’t be overwritten). - For unions: if any non-static data member is
constor a reference (since those can’t be moved into).
If any of these are true, the compiler marks the implicit move assignment as deleted—meaning it won’t exist at all, and trying to use it will throw a compile error.
Why These Rules Exist?
C++ follows the "rule of zero" philosophy here: if you don’t need to customize copy/move/destructor behavior, the compiler gives you safe, default implementations that work for most simple classes. But as soon as you declare any of these special functions, the compiler assumes you’re taking control of resource management, so it stops generating the others automatically to avoid conflicts or unexpected behavior (like a compiler-generated move that clashes with your custom destructor).
Quick Examples to Drive It Home
Case 1: Implicit Move Assignment Works
This struct has no custom special functions, so the compiler generates a move assignment operator for it:
struct SimpleData { int id; std::string label; }; // This works perfectly—compiler uses the auto-generated operator=(SimpleData&&) SimpleData a; SimpleData b = {42, "test"}; a = std::move(b); // b's resources are moved to a efficiently
Case 2: Implicit Move Assignment Is NOT Generated
This struct has a custom destructor, so the compiler skips generating the move assignment:
struct CustomCleanup { int* buffer; CustomCleanup() : buffer(new int[100]) {} ~CustomCleanup() { delete[] buffer; } // User-declared destructor }; CustomCleanup x; CustomCleanup y; x = std::move(y); // This won't use move assignment—falls back to copy assignment (or errors if copy is deleted)
内容的提问来源于stack exchange,提问作者user3613174

