c++  复制消除问题解决示例详析

 更新时间:2023年08月10日 10:51:01   作者:hedzr  
这篇文章主要为大家介绍了c++  复制消除问题解决示例详析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

错误示范

push_back 这么写是错的:

template<class T>
  class threaded_message_queue {
    public:
    using lock = std::unique_lock<std::mutex>;
    void push_back(T t) {
      {
        lock l(_m);
        _data.push_back(std::move(t));
      }
      _cv.notify_one();
    }
  }
};//

入参 T t 导致了调用者在这里会发生一次临时对象 TMP 的复制,稍后在函数退出点处 TMP 还会被隐式析构。所以这个写法不是良构

至于函数体中的 std::move(t) 也就是聊胜于无了,它并不会让 t 少掉 TMP 的复制,仅仅只是少掉了 t 到 _data 的一次复制而已。

正确工作

做模板类开发时,经常会遇到 push_back 的这种场景。

正确的 push_back 应该包含左值复制和右值移动两种语义,一般来说像是这样子:

template<class T>
  class threaded_message_queue {
    public:
    using lock = std::unique_lock<std::mutex>;
    void emplace_back(T &&t) {
      {
        lock l(_m);
        _data.template emplace_back(std::move(t));
      }
      _cv.notify_one();
    }
    void push_back(T const &t) {
      {
        lock l(_m);
        _data.push_back(t);
      }
      _cv.notify_one();
    }
  }
};

注意右值加上移动语义才是一对搭配。T t 和移动语义在一起只是一种错觉。

你还可以加上一个 push_back 的移动语义:

void push_back(T &&t) {
      {
        lock l(_m);
        _data.template emplace_back(std::move(t));
      }
      _cv.notify_one();
    }

这是因为按照约定,emplace_back 通常采用模板变参并实现 T 类的原位构造。这个话题我在 C++ 中的原位构造函数及完美转发 - 写我们自己的 variant 包装类 已经有过一定的讨论,这里就不详述了。

X-class

hicc::debug::X 是一个专门用来调试 RVO,In-place construction,Copy Elision 等等特性的工具类,它平平无奇,只不过是在若干位置埋点冰打印 stdout 文字而已,这可以让我们直观观察到哪些行为实际上发生了。

X-class 在构造函数的入参部分有相似的构造:

namespace hicc::debug {
    class X {
        std::string _str;
        void _ct(const char *leading) {
            printf("  - %s: X[ptr=%p].str: %p, '%s'\n", leading, (void *) this, (void *) _str.c_str(), _str.c_str());
        }
    public:
        X() {
            _ct("ctor()");
        }
        ~X() {
            _ct("dtor");
        }
        X(std::string &&s)
            : _str(std::move(s)) {
            _ct("ctor(s)");
        }
        X(std::string const &s)
            : _str(s) {
            _ct("ctor(s(const&))");
        }
        X &operator=(std::string &&s) {
            _str = std::move(s);
            _ct("operator=(&&s)");
            return (*this);
        }
        X &operator=(std::string const &s) {
            _str = s;
            _ct("operator=(const&s)");
            return (*this);
        }
        const char *c_str() const { return _str.c_str(); }
        operator const char *() const { return _str.c_str(); }
    };
} // namespace hicc::debug

以上就是c++ 复制消除问题解决示例详析的详细内容,更多关于c++ 复制消除问题的资料请关注脚本之家其它相关文章!

相关文章

  • C语言数据结构通关时间复杂度和空间复杂度

    C语言数据结构通关时间复杂度和空间复杂度

    对于一个算法,其时间复杂度和空间复杂度往往是相互影响的,当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间,这篇文章主要给大家介绍了关于C语言时间复杂度、空间复杂度的相关资料,需要的朋友可以参考下
    2022-04-04
  • C/C++中四种常用查找算法的实现

    C/C++中四种常用查找算法的实现

    C语言作为一种强大的编程语言,提供了多种搜索算法的实现方式,本文将介绍C语言中的四种常见搜索算法并提供每种算法的简单实现示例,需要的小伙伴可以参考下
    2023-11-11
  • 详解C语言之操作符

    详解C语言之操作符

    这篇文章主要以图文结合的方式为大家详细介绍了C语言的操作符知识,感兴趣的小伙伴们可以参考一下,希望能给你带来帮助
    2021-11-11
  • C语言深入浅出解析二叉树

    C语言深入浅出解析二叉树

    二叉树可以简单理解为对于一个节点来说,最多拥有一个上级节点,同时最多具备左右两个下级节点的数据结构。本文将详细介绍一下C++中二叉树的实现和遍历,需要的可以参考一下
    2022-03-03
  • 理解数据结构

    理解数据结构

    本文是对数据结构对编程的重要性,数据结构对数据存储,数据处理,内存工作,从宏观上理解数据结构
    2016-07-07
  • Qt qml实现动态轮播图效果

    Qt qml实现动态轮播图效果

    这篇文章主要为大家详细介绍了Qt和qml实现动态轮播图效果的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2024-12-12
  • C++深入探究类与对象之友元与运算符重载

    C++深入探究类与对象之友元与运算符重载

    友元就是让一个函数或者类,访问另一个类中的私有成员;打个比方,这相当于是说:朋友是值得信任的,所以可以对他们公开一些自己的隐私,运算符重载的实质就是函数重载或函数多态,运算符重载是一种形式的C++多态,目的在于让人能够用同名的函数来完成不同的基本操作
    2022-04-04
  • OpenCV中C++函数imread读取图片的问题及解决方法

    OpenCV中C++函数imread读取图片的问题及解决方法

    利用C++函数imread读取图片的时候返回的结果总是空,而利用C函数cvLoadImage时却能读取到图像。怎么回事?今天小编通过本教程给大家简单说明原因
    2017-03-03
  • VS2019配置BOOST的方法(v1.70.0库)

    VS2019配置BOOST的方法(v1.70.0库)

    这篇文章主要介绍了VS2019配置BOOST的方法(v1.70.0库),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • C语言清除scanf()缓存的案例讲解

    C语言清除scanf()缓存的案例讲解

    今天小编就为大家分享一篇关于C语言清除scanf()缓存的案例讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03

最新评论