用好 C++11 move语义

使用方法原始文档:move

右值引用与使用:move

条条道路通罗马

假设你都阅读并理解了上述2个文档,那么就知道了对右值主要解决拷贝的性能问题。
但是只要你实现并运用好swap函数或者使用常量指针当做返回参数,也可以达到0拷贝。
当然如果你觉得swap和指针参数会使得代码难看,以及写代码稍微复杂,那么可以使用move右值语义。

如何写好一个有move语义的自定义数据结构

在C++11标准中,编译器会自定义数据结构默认生成6个函数: 无参构造,拷贝构造,赋值,右值构造,右值赋值,析构函数,如下:

struct DefaultNote {
    // 无参构造
    DefaultNote() {

    }
    // 析构
    ~DefaultNote() {

    }
    // 拷贝构造
    DefaultNote(const DefaultNote& o) {
        printf("default copy construct\n");
    }
    // 赋值
    DefaultNote& operator = (const DefaultNote& o) {
        printf("default assign\n");
        return *this;
    }
    // 右值构造
    DefaultNote(DefaultNote&& o) {
        printf("default right value copy construct\n");
    }
    // 右值赋值
    DefaultNote& operator = (DefaultNote&& o) {
        printf("default right value assign\n");
        return *this;
    }
    /* 

    */       
};   

注意没有赋值构造这一说法:

DefaultNote node;  
// 此处是调用的拷贝构造  
DefaultNote node2 = node;  
// 相当于  
// DefaultNote node2(node);  

当我们自定义数据结构的时候,要么都不定义以上任何函数,要么就全部定义以上所有6个函数,否则编译器默认函数的加入会使问题变得不可控。
如果需要自定义某个函数,又想充分利用编译器自动生成的函数,而又想数据结构安全,必须全面了解编译器干了什么。
如下表,整理了用户自定义函数和编译器默认生成函数的关系。
user-def: 表示用户自定义
delete: 表示编译器不允许调用此函数,调用此函数编译错
default: 表示编译器生成的默认函数
左值函数:拷贝构造函数,赋值函数
右值函数:右值构造函数,右值赋值函数
构造函数

总结:

  • 析构函数完全置身于这些构造函数和赋值函数的纠纷中
  • 用户自定义了构造函数(包括拷贝构造和右值构造)后,编译器拒绝生成无参构造函数
  • 用户自定义了某个函数,完全以这个函数为全部,编译器对于这个函数不会生成任何附加代码
    例如:定义了右值构造,那么结构体内的变量的右值构造也需要手动调用,否则结构体内的变量什么构造函数都不会调用
  • 拷贝构造和赋值函数对等互不影响
  • 一旦自定义了一个左值函数,右值函数like对应的左值函数
  • 一旦自定义了一个右值函数,左值函数delete,另一个右值函数like对应的左值函数
  • STL类型的右值赋值是调用的swap函数
  • 为保持和STL一致,自定义右值赋值函数最好也调用swap函数

测试Demo

#include <vector>
#include <iostream>

void Print(const std::string& s) {
    printf("%s\n", s.c_str());
}
void testSTLStruct () {
    std::string s1 = "s1";
    // s11偷了s1的 impl
    std::string s11(std::move(s1));
    Print(s1);
    Print(s11);

    std::string s2 = "s2";
    std::string s22 = "s22";
    // 实际调用swap函数
    s22 = std::move(s2);
    Print(s2);
    Print(s22);
};


void testUserBaseStruct() {
    struct DefaultNote {
        // 无参构造
        DefaultNote() {

        }
        // 析构
        ~DefaultNote() {

        }
        // 拷贝构造
        DefaultNote(const DefaultNote& o) {
            printf("default copy construct\n");
        }
        // 赋值
        DefaultNote& operator = (const DefaultNote& o) {
            printf("default assign\n");
            return *this;
        }
        // 右值构造
        DefaultNote(DefaultNote&& o) {
            printf("default right value copy construct\n");
        }
        // 右值赋值
        DefaultNote& operator = (DefaultNote&& o) {
            printf("default right value assign\n");
            return *this;
        }
    };

    struct Node {
        Node() = default;
#if 1
        Node(const Node& o) {
            printf("user copy construct\n");
        }
#endif

#if 0
        Node& operator = (const Node& o) {
            printf("user assign\n");
            return *this;
        }
#endif

#if 0
        Node(Node&& o) {
            printf("user right value copy construct\n");
        }
#endif 

#if 0
        Node& operator = (Node&& o) {
            printf("user right value assign\n");
            return *this;
        }
#endif
        DefaultNote base;
    };


    Node node;
    Node node1(node);
    node = node;
    Node node2(std::move(node));
    node = std::move(node);
}

int main(int argc, char **argv) {
    testUserBaseStruct();
    testSTLStruct();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值