c+ - Qu'est-ce qui bouge la sémantique

Mots clés : c++c++-faqc++11move-semanticsc++

meilleur 3 Réponses c+ - Qu'est-ce qui bouge la sémantique

vote vote

90

#include <cstring> #include <algorithm>  class string {     char* data;  public:      string(const char* p)     {         size_t size = std::strlen(p) + 1;         data = new char[size];         std::memcpy(data, p, size);     } 
    ~string()     {         delete[] data;     }      string(const string& that)     {         size_t size = std::strlen(that.data) + 1;         data = new char[size];         std::memcpy(data, that.data, size);     } 
string a(x);                                    // Line 1 string b(x + y);                                // Line 2 string c(some_function_returning_a_string());   // Line 3 
    string(string&& that)   // string&& is an rvalue reference to a string     {         data = that.data;         that.data = nullptr;     } 
    string& operator=(string that)     {         std::swap(data, that.data);         return *this;     } }; 
vote vote

85

class cannot_benefit_from_move_semantics {     int a;        // moving an int means copying an int     float b;      // moving a float means copying a float     double c;     // moving a double means copying a double     char d[64];   // moving a char array means copying a char array      // ... }; 
{     std::auto_ptr<Shape> a(new Triangle);     // ...     // arbitrary code, could throw exceptions     // ... }   // <--- when a goes out of scope, the triangle is deleted automatically 
auto_ptr<Shape> a(new Triangle);        +---------------+       | triangle data |       +---------------+         ^         |         |         |   +-----|---+   |   +-|-+ | a | p | | | |   |   +---+ |   +---------+  auto_ptr<Shape> b(a);        +---------------+       | triangle data |       +---------------+         ^         |         +----------------------+                                |   +---------+            +-----|---+   |   +---+ |            |   +-|-+ | a | p |   | |          b | p | | | |   |   +---+ |            |   +---+ |   +---------+            +---------+ 
auto_ptr(auto_ptr& source)   // note the missing const {     p = source.p;     source.p = 0;   // now the source no longer owns the object } 
auto_ptr<Shape> a(new Triangle);   // create triangle auto_ptr<Shape> b(a);              // move a into b double area = a->area();           // undefined behavior 
auto_ptr<Shape> make_triangle() {     return auto_ptr<Shape>(new Triangle); }  auto_ptr<Shape> c(make_triangle());      // move temporary into c double area = make_triangle()->area();   // perfectly safe 
auto_ptr<Shape> variable(expression); double area = expression->area(); 
auto_ptr<Shape> c(make_triangle());                                   ^ the moved-from temporary dies right here 
            lvalue   const lvalue   rvalue   const rvalue ---------------------------------------------------------               X&          yes const X&    yes      yes            yes      yes X&&                                 yes const X&&                           yes      yes 
void some_function(std::string&& r);  some_function("hello world"); 
template<typename T> class unique_ptr {     T* ptr;  public:      T* operator->() const     {         return ptr;     }      T& operator*() const     {         return *ptr;     } 
    explicit unique_ptr(T* p = nullptr)     {         ptr = p;     }      ~unique_ptr()     {         delete ptr;     } 
    unique_ptr(unique_ptr&& source)   // note the rvalue reference     {         ptr = source.ptr;         source.ptr = nullptr;     } 
unique_ptr<Shape> a(new Triangle); unique_ptr<Shape> b(a);                 // error unique_ptr<Shape> c(make_triangle());   // okay 
    unique_ptr& operator=(unique_ptr&& source)   // note the rvalue reference     {         if (this != &source)    // beware of self-assignment         {             delete ptr;         // release the old resource              ptr = source.ptr;   // acquire the new resource             source.ptr = nullptr;         }         return *this;     } }; 
    unique_ptr& operator=(unique_ptr source)   // note the missing reference     {         std::swap(ptr, source.ptr);         return *this;     } }; 
unique_ptr<Shape> a(new Triangle); unique_ptr<Shape> b(a);              // still an error unique_ptr<Shape> c(std::move(a));   // okay 
        expressions           /     \          /       \         /         \     glvalues   rvalues       /  \       /  \      /    \     /    \     /      \   /      \ lvalues   xvalues   prvalues 
unique_ptr<Shape> make_triangle() {     return unique_ptr<Shape>(new Triangle); }          \-----------------------------/                   |                   | temporary is moved into c                   |                   v unique_ptr<Shape> c(make_triangle()); 
unique_ptr<Shape> make_square() {     unique_ptr<Shape> result(new Square);     return result;   // note the missing std::move } 
unique_ptr<Shape>&& flawed_attempt()   // DO NOT DO THIS! {     unique_ptr<Shape> very_bad_idea(new Square);     return std::move(very_bad_idea);   // WRONG! } 
class Foo {     unique_ptr<Shape> member;  public:      Foo(unique_ptr<Shape>&& parameter)     : member(parameter)   // error     {} }; 
class Foo {     unique_ptr<Shape> member;  public:      Foo(unique_ptr<Shape>&& parameter)     : member(std::move(parameter))   // note the std::move     {} }; 
X::X(const X&);              // copy constructor X& X::operator=(const X&);   // copy assignment operator X::~X();                     // destructor 
X::X(X&&);                   // move constructor X& X::operator=(X&&);        // move assignment operator 
X& X::operator=(X source)    // unified assignment operator {     swap(source);            // see my first answer for an explanation     return *this; } 
template<typename T> void foo(T&&); 
foo(make_triangle());   // T is unique_ptr<Shape>, T&& is unique_ptr<Shape>&& unique_ptr<Shape> a(new Triangle); foo(a);                 // T is unique_ptr<Shape>&, T&& is unique_ptr<Shape>& 
#include <type_traits>  template<typename T> typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type foo(T&&); 
template<typename T> typename std::remove_reference<T>::type&& move(T&& t) {     return static_cast<typename std::remove_reference<T>::type&&>(t); } 
vote vote

80

Matrix multiply(const Matrix &a, const Matrix &b); 
Matrix r = multiply(a, b); 

Questions similaires