c++中ref的作用示例解析

目录
  • 正文
    • 示例1:
      • 输出:
      • 输出:
  • 总结

正文

C++11 中引入 std::ref 用于取某个变量的引用,这个引入是为了解决一些传参问题。

我们知道 C++ 中本来就有引用的存在,为何 C++11 中还要引入一个 std::ref 了?主要是考虑函数式编程(如 std::bind)在使用时,是对参数直接拷贝,而不是引用。下面通过例子说明

示例1:

#include <functional>
#include <iostream>
void f(int& n1, int& n2, const int& n3)
{
    std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    ++n1; // increments the copy of n1 stored in the function object
    ++n2; // increments the main()'s n2
    // ++n3; // compile error
}

int main()
{
    int n1 = 1, n2 = 2, n3 = 3;
    std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
    n1 = 10;
    n2 = 11;
    n3 = 12;
    std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
    bound_f();
    std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}

输出:

Before function: 10 11 12
In function: 1 11 12
After function: 10 12 12

上述代码在执行 std::bind 后,在函数 f() 中n1 的值仍然是 1,n2 和 n3 改成了修改的值,说明 std::bind 使用的是参数的拷贝而不是引用,因此必须显示利用 std::ref 来进行引用绑定。具体为什么 std::bind 不使用引用,可能确实有一些需求,使得 C++11 的设计者认为默认应该采用拷贝,如果使用者有需求,加上 std::ref 即可。

#include <thread>
#include <iostream>
#include <string>
void threadFunc(std::string &str, int a)
{
    str = "change by threadFunc";
    a = 13;
}

int main()
{
    std::string str("main");
    int a = 9;
    std::thread th(threadFunc, std::ref(str), a);

    th.join();

    std::cout<<"str = " << str << std::endl;
    std::cout<<"a = " << a << std::endl;

    return 0;
}

该程序创建一个线程 th,调用带有两个参数的 threadFunc 函数:一个是 std::string 对象 str 的引用,另一个是整数 a。函数 threadFunc 修改字符串 str 为 "change by threadFunc",但不修改整数 a。最后在主线程中输出 stra 的值。

输出:

str = change by threadFunc
a = 9

可以看到,和 std::bind 类似,多线程的 std::thread 也是必须显式通过 std::ref 来绑定引用进行传参,否则,形参的引用声明是无效的。

总结

std::ref 是一个 C++ 标准库函数模板,它将对象的引用转换为可复制的可调用对象。

std::ref 用于将对象的引用传递给函数或线程等可调用对象的参数。如果不使用 std::ref,那么函数或线程会将对象的副本传递给可调用对象的参数,这可能会导致无法预期的结果,因为对该副本的修改不会影响原始对象。通过使用 std::ref,可以确保可调用对象引用的是原始对象,因此对该对象的修改将影响原始对象。

需要注意的是,使用 std::ref 前必须确保原始对象的生命周期至少与可调用对象相同,否则会导致悬空引用。另外,std::ref 不能用于将指向临时对象或将过时对象的引用传递给可调用对象。

总之,std::ref 的作用是将对象的引用转换为可复制的可调用对象,使得在函数或线程等可调用对象中引用原始对象,而不是其副本。

以上就是c++中ref的作用示例解析的详细内容,更多关于c++ ref作用的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++标准之(ravalue reference) 右值引用介绍

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了CopyElision.RVO(包括NRVO)等编译器优化技术,它们可以防止某些情况下临时对象产生和拷贝.下面简单地介绍一下CopyElision.RVO,对此不感兴趣的可以直接跳过: (1)CopyElision CopyElision技术是为了防止某些不必要的临时对象产生和拷贝,例如: 复制代码 代码如下: structA{ A(

  • C++预定义的流对象基本示例详解

    目录 C++预定义的流对象 示例说明 总结: C++预定义的流对象 C++预定义的流对象是可用于输入和输出的数据流向对象.它们是在C++语言中内置的,可以使用标准库的iostream头文件来调用这些流对象. 在这篇文章中,我们将介绍C++预定义的流对象,并提供一些示例说明. 示例说明 cin: cin是标准输入流对象,用于从控制台读取输入. 示例: int num; cout << "Enter a number: "; cin >> num; cout <

  • C++类与对象及构造函数析构函数基础详解

    目录 C++类与对象 类的定义 对象的创建 构造函数和析构函数 访问修饰符 继承 多态 成员变量与成员方法 总结 C++类与对象 C++是一门面向对象的编程语言.在C++中,我们可以利用类来创建对象,并在编程时实现抽象.封装.继承和多态等面向对象的特性.下面是关于C++类和对象的学习内容及示例. 类的定义 在C++中,我们可以通过定义类来描述某种对象的属性和行为.类的定义可以分为两部分:声明和实现. 声明部分:类的声明部分通常包含类名.类成员(属性和方法)的声明.访问权限的修饰符等.下面是一个简

  • 解析C++11的std::ref、std::cref源码

    1.源码准备 本文是基于gcc-4.9.0的源代码进行分析,std::ref和std::cref是C++11才加入标准的,所以低版本的gcc源码是没有这两个的,建议选择4.9.0或更新的版本去学习,不同版本的gcc源码差异应该不小,但是原理和设计思想的一样的,下面给出源码下载地址 http://ftp.gnu.org/gnu/gcc 2.std::ref和std::cref的作用 C++本身就有引用(&),那为什么C++11又引入了std::ref(或者std::cref)呢? 主要是考虑函数式

  • C++ 三种继承方式及好处示例详解

    目录 C++继承 公有继承 保护继承 私有继承 继承带来的好处 总结 C++继承 C++继承是面向对象编程中非常常见的一个概念,它提供了一种将一个类的特性引入另一个类的机制.在继承中,被继承的类称为基类或父类,继承它的类称为派生类或子类. 在C++中,继承通过关键字“public”.“protected”.“private”来实现不同层次的继承,其中“public”表示公有继承,“protected”表示保护继承,“private”表示私有继承.以下是C++中三种继承方式的示例: 公有继承 公有

  • C++20中的结构化绑定类型示例详解

    目录 C++20中新增了一个非常有用的特性 结构化绑定概念 结构化绑定类型 数组 Pair 结构体 实现一个可以被结构化绑定的类元组类型 C++20中新增了一个非常有用的特性 结构化绑定(Structured Binding).它可以让我们方便地从一个容器类型中取出元素并绑定到对应的变量中,使得代码更加简洁.易读.接下来,本文将分别介绍结构化绑定的概念.类型以及如何实现一个可以被结构化绑定的类元组类型. 结构化绑定概念 结构化绑定是C++20中的一个语言特性,允许将一个结构体或者其他类似类型的容

  • C++函数模板学习示例教程指南

    目录 C++函数模板学习指南 1. 函数模板的定义 2. 函数模板的使用 3. 函数模板的特化 4. 函数模板的偏特化 6. 非类型模板参数 7. 函数模板的局限性 总结 C++函数模板学习指南 C++函数模板是一种高效的代码复用机制,它允许我们定义一种可以用于多种类型的函数,而不必为每种类型都编写一个函数.本篇文章将介绍C++函数模板的基本使用.我们将逐步讨论函数模板的定义.使用.特化和偏特化. 1. 函数模板的定义 函数模板的定义基本语法如下: template <typename T>

  • C++获取多浏览器上网历史记录示例代码(支持获取IE/Chrome/FireFox)

    复制代码 代码如下: // FileName: BrowsHistory.h // ------------------------------------------------------------------------------------------------------------------------// Remarks://   BrowsHistory对象应该设置成全局,或者静态:防止还没有获取完网址,对象就析构了:// ------------------------

  • c++中ref的作用示例解析

    目录 正文 示例1: 输出: 输出: 总结 正文 C++11 中引入 std::ref 用于取某个变量的引用,这个引入是为了解决一些传参问题. 我们知道 C++ 中本来就有引用的存在,为何 C++11 中还要引入一个 std::ref 了?主要是考虑函数式编程(如 std::bind)在使用时,是对参数直接拷贝,而不是引用.下面通过例子说明 示例1: #include <functional> #include <iostream> void f(int& n1, int&

  • Oracle PL/SQL中异常高级特性示例解析

    PL/SQL(Procedural Language/SQL,过程语言/SQL)是结合了Oracel过程语言和结构化查询语言(SQL)的一种扩展语言. 优点: (1)PL/SQL具有编程语言的特点,它能把一组SQL语句放到一个模块中,使其更具模块化种序的特点. (2)PL/SQL可以采用过程性语言控制程序的结构. (3)PL/SQL有自动处理的异常处理机制. (4)PL/SQL程序块具有更好的可移植性,可移植到另一个Oracle数据库中. (5)PL/SQL程序减少了网络的交互,有助于提高程序性

  • Java 在PDF中添加骑缝章示例解析

    骑缝章是用于往来业务合同,以确保合同真实.有效的印章加盖方法,是一种防范风险的重要方式.在Java程序中,可以通过使用工具来辅助加盖这种骑缝章. 工具:Free Spire.PDF for Java (免费版) 工具获取及jar文件导入: 方式1:通过官网下载jar包,并解压,手动导入lib文件夹下的Spire.Pdf.jar文件. 方式2:通过创建Maven程序,在pom.xml中配置maven仓库路径并指定Free Spire.PDF for Java 的依赖,配置完成后,在IDEA中,点击

  • Kotlin中@JvmOverloads注解作用示例介绍

    在Kotlin中@JvmOverloads注解的作用:指示Kotlin编译器为此函数生成替换默认参数值的重载. 如果一个方法有N个参数,其中M个具有默认值,则会生成M个重载. 第一个重载采用N-1个参数(最后一个采用默认值),第二个采用N-2个参数,依此类推. 因为在 Kotlin 中可以调用具有默认参数值的方法或者构造函数,但是在 Java 代码调用相应 Kotlin 代码却不行,及Java 代码不能调用Kotlin 中定义的具有默认参数的重载函数或构造函数.@JvmOverloads 就是用

  • Vue中key的作用示例代码详解

    Vue中key的作用 key的特殊attribute主要用在Vue的虚拟DOM算法,在新旧Nodes对比时辨识VNodes.如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改.复用相同类型元素的算法,而使用key时,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素.此外有相同父元素的子元素必须有独特的key,重复的key会造成渲染错误. 描述 首先是官方文档的描述,当Vue正在更新使用v-for渲染的元素列表时,它默认使用就地更新的策略,如果数据项的

  • electron 中 webview的使用示例解析

    目录 正文 获取webview的dom webview 页面 webview页面的代码 新建public/preload.js文件 监听页面对否显示 禁止打开新窗口 刷新页面 上一页 下一页 正文 webview 想必都有所了解,比如:微信小程序嵌套H5 那么我们在electron中怎么使用webview呢? 我们先跟着官方文档展示一下,看是否能有效果: 若要在应用程序中嵌入网页, 请将 webview 标签添加到应用程序的被嵌入页面中 (这是将显示外来内容的应用程序页). 在最简单的例子中,

  • Android中Parcelable的作用实例解析

    在android提供了一种类型:Parcel.被用作封装数据的容器,封装后的数据可以通过Intent或IPC传递. 除了基本类型以外,只有实现了Parcelable接口的类才能被放入Parcel中.   Parcelable实现要点:需要实现三个东西 1)writeToParcel 方法.该方法将类的数据写入外部提供的Parcel中.声明如下: writeToParcel (Parcel dest, int flags) 具体参数含义见javadoc 2)describeContents方法.没

  • Java中Volatile的作用实例解析

    Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分. 锁 锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility). 互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用

  • C# DES加密算法中向量的作用详细解析

    DES一共就有4个参数参与运作:明文.密文.密钥.向量.为了初学者容易理解,可以把4个参数的关系写成:密文=明文+密钥+向量:明文=密文-密钥-向量.为什么要向量这个参数呢?因为如果有一篇文章,有几个词重复,那么这个词加上密钥形成的密文,仍然会重复,这给破解者有机可乘,破解者可以根据重复的内容,猜出是什么词,然而一旦猜对这个词,那么,他就能算出密钥,整篇文章就被破解了!加上向量这个参数以后,每块文字段都会依次加上一段值,这样,即使相同的文字,加密出来的密文,也是不一样的,算法的安全性大大提高!

  • web项目开发中2个Token原因解析及示例代码

    目录 问题: 项目中2个Token, 一个时效2个小时(简称:短Token), 另一个时效14天(简称:长Token), 为什么要用2个Token? 解答: 1.基于安全性, 防止Token泄露的考虑, 服务器资源中所有的请求都只能使用短Token, 并且短Token只有2小时时效; 这个方法依然无法完全解决防止Token泄露的问题, 只是在一定程度上提高防止Token泄露的安全性; 长Token的作用只有一个, 就是短Token时效了的时候, 用长Token去请求获取新的短Token, 只有这

随机推荐