Special member functions (copy/move constructor) - C++11, 21 of n

Copy/move constructor

  • First, what's wrong with this copy constructor ? Infinite recursive ?
    class A {
    public:
        A(A a) {...}
    };
  • If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted. [The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor ???]. Example:
    class A {
    public:
        A() {
        }
        A(A&& a) {
        }
    };

    int main() {
        A a;
        A b(a); // error, A::A(const A&)’ is implicitly declared as
                    // deleted because ‘A’ declares a move constructor 

    }
  • The implicitly-declared copy constructor for a class X will have the form
    X::X(const X&)
    if
    — each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
    — for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&. Otherwise, the implicitly-declared copy constructor will have the form X::X(X&)
  • If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if
    • X does not have a user-declared copy constructor
    • X does not have a user-declared copy assignment operator
    • X does not have a user-declared move assignment operator, and
    • X does not have a user-declared destructor
      Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor.
  • A defaulted copy/move constructor for a class X is defined as deleted if X has:
    • a variant member with a non-trivial corresponding constructor and X is a union-like class
    • a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution, as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor
    • a direct or virtual base class B that cannot be copied/moved because overload resolution as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor
    • any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor, or,
    • for the copy constructor, a non-static data member of rvalue reference type
  • The implicitly-defined copy/move constructor for a non-union class X performs a member wise copy/move of its bases and members. Note: brace-or-equal-initializers of non-static data members are ignored. Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type
    • if the member is an array, each element is direct-initialized with the corresponding subobject of x
    • if a member m has rvalue reference type T&&, it is direct-initialized with static_cast<T&&>(x.m)
    • otherwise, the base or member is direct-initialized with the corresponding base or member of x.
  • The implicitly-defined copy/move constructor for a union X copies the object representation of X.
  • (COPY ELISION) When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
    • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter [Edit, function parameter or catch-clause parameter doesn't apply COPY ELISION]with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
    • when a temporary class object that has not been bound to a reference would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move
    • in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object can be omitted by constructing the automatic object directly into the exception object
    • when the exception-declaration of an exception handler declares an object of the same type (except for cv-qualification) as the exception object, the copy/move operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration.
  • When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter,and the object to be copied is designated by an lvalue,overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue (WHY ? Because if there is no elision happened, there will be an new object constructed and this new object will be rvalue). If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again,considering the object as an lvalue. [ Note:This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]. Example:

    class Thing {
    public:
        Thing();
        ~Thing();
        Thing(Thing&&);
    private:
        Thing(const Thing&);
    };
    Thing f(bool b) {
        Thing t;
        if (b)
            throw t; // OK: Thing(Thing&&) used (or elided) to throw t
                          // "t" is a lvalue, but treats it as a rvalue when performing overload resolution lookup,
                          // Thing(Thing&&) is picked for moving construction and the move-ctor is defined
                         // and accessible

        return t; // OK: Thing(Thing&&) used (or elided) to return t
    }
    Thing t2 = f(false); // OK: Thing(Thing&&) used (or elided) to construct t2


    class Thing {
    public:
        Thing();
        ~Thing();
        Thing(const Thing&);
    private:
        Thing(Thing&&); 
    };
    Thing f(bool b) {
        Thing t;
        if (b)
            throw t; // ERROR. 
        return t; // ERROR.  When doing overload resolution, treat "t" as rvalue,
                      // so Thing(Thing&&) is picked to do the move construction,
                      // but Thing(Thing&&) is private, not accessible. Hence reporting error.
                      // (This check is performed regardless if copy-elide will happen)

    }
    Thing t2 = f(false); // ERROR


    class Thing {
    public:
        Thing();
        ~Thing();
        Thing(const Thing&);
        Thing(Thing&&) = delete; 
    };
    Thing f(bool b) {
        Thing t;
        if (b)
            throw t; // ERROR. 
        return t; // ERROR.  When doing overload resolution, treat "t" as rvalue,
                      // so Thing(Thing&&) is picked to do the move construction, 

                      // but Thing(Thing&&) is delete, not accessible. Hence reporting error.
                     // (This check is performed regardless if copy-elide will happen)

    }
    Thing t2 = f(false); // ERROR

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值