文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

函数参数的最佳传递方式与现代C++的规则

2024-11-30 04:57

关注

使用移动语义实现 Swap 函数

移动语义(Move Semantics)能够提升性能的一个例子是实现一个交换(swap)函数模板,该模板交换两个对象。不使用移动语义的实现如下:

 template 
 void swapCopy(T& a, T& b) {
     T temp { a };
     a = b;
     b = temp;
 }

这种实现方式会影响性能,尤其是当类型T的拷贝开销很大时。使用移动语义,实现可以避免所有拷贝:

 template 
 void swapMove(T& a, T& b) {
     T temp { std::move(a) };
     a = std::move(b);
     b = std::move(temp);
 }

这就是标准库中 std::swap() 的实现方式。

在返回语句中使用 std::move()

如果返回语句的形式为 return object;,并且 object 是一个局部变量、函数参数或临时值,编译器会将其视为右值表达式,并触发返回值优化(RVO)。此外,如果 object 是一个局部变量,命名返回值优化(NRVO)也可能发生。RVO和NRVO都是拷贝省略(Copy Elision)的形式,使得从函数返回对象非常高效。

使用 std::move() 来返回对象会怎样呢?无论你写 return object; 还是 return std::move(object);,在两种情况下,编译器都会将其视为右值表达式。然而,使用 std::move(),编译器无法再应用RVO或NRVO,这可能会对性能产生重大影响!

所以,请记住以下规则:当从函数返回局部变量或参数时,只需写 return object;,不要使用 std::move()。

参数的最佳传递方式

到目前为止,建议对非原始类型的函数参数使用 const 引用参数,以避免不必要的昂贵拷贝。然而,随着右值的引入,情况略有变化。想象一个无论如何都会拷贝其参数的函数。现在,你可能想要添加一个重载,以避免在右值的情况下进行任何拷贝。这里有一个例子:

 class DataHolder {
 public:
     void setData(const std::vector& data) {
         m_data = data;
    }
     void setData(std::vector&& data) {
         m_data = std::move(data);
    }
 
 private:
     std::vector m_data;
 };

但是,有一种更好的方式,涉及使用传值的单个方法。对于函数本来就会拷贝的参数,使用传值语义是最优的选择。如果传入左值,它恰好被拷贝一次。如果传入右值,不会进行拷贝。

零规则(Rule of Zero)

在现代C++中,应该遵循所谓的零规则(Rule of Zero)。这个规则指出,你应该设计你的类,使它们不需要任何特殊的成员函数。怎么做到这一点呢?基本上,你应该避免使用任何老式的动态分配内存。相反,应该使用像标准库容器这样的现代构造。例如,使用 vector> 替代 Spreadsheet 类中的 SpreadsheetCell** 数据成员。vector 会自动处理内存,因此不需要任何特殊的成员函数。

现代C++中推荐使用零规则,而五规则(Rule of Five)应该限于自定义的资源获取是初始化(RAII)类。RAII类获取资源的所有权,并在合适的时候处理它的释放。这是一种设计技术,例如,由 vector 和 unique_ptr 使用,并在后续的章节中进一步讨论。

静态方法和 const 方法是 C++ 中的两个重要概念,它们各自在不同的情况下发挥着重要作用。

静态方法(Static Methods)

静态方法是那些不依赖于类的实例而存在的方法。与静态数据成员类似,静态方法适用于整个类,而不是每个对象。在实现静态方法时,需要注意以下几点:

例如:

Foo::bar();

const 方法(Const Methods)

const 方法是保证不会修改任何数据成员的方法。如果你有一个 const 对象,引用到 const 或指向 const 的指针,编译器不允许你调用除非是 const 方法的任何方法。通过在方法声明时使用 const 关键字,可以保证该方法不会修改任何数据成员。

例如:

 double SpreadsheetCell::getValue() const {
     return m_value;
 }
 
 std::string SpreadsheetCell::getString() const {
     return doubleToString(m_value);
 }

mutable 数据成员(Mutable Data Members)

有时,你可能会编写一个在逻辑上是 const 的方法,但该方法恰好会更改对象的某个数据成员。这种修改对用户可见的数据没有影响,但从技术上讲是一种更改,因此编译器不允许你将方法声明为 const。在这种情况下,可以使用 mutable 关键字来声明那些即使在 const 方法中也可以被修改的数据成员。

例如:

 class SpreadsheetCell {
     // ...
 private:
     double m_value { 0 };
     mutable size_t m_numAccesses { 0 };
     // ...
 };
 
 double SpreadsheetCell::getValue() const {
     m_numAccesses++;
     return m_value;
 }
 
 std::string SpreadsheetCell::getString() const {
     m_numAccesses++;
     return doubleToString(m_value);
 }

在这个例子中,即使 getValue() 和 getString() 被标记为 const,它们也可以修改 m_numAccesses,因为它被声明为 mutable。这允许方法在保持其 const 性质的同时,对某些数据成员进行修改。

来源:coding日记内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯