【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例)

这篇具有很好参考价值的文章主要介绍了【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

几种传参方式简单对比

  1. 传值
    1.1 参数形式:void fun(vector<int> v);
    1.2 函数调用:fun(v);
    1.3 函数内使用:cout << v[1];
    1.4 是否可以改变函数外对象的值:否
    1.5 是否会调用拷贝构造函数:
  2. 传指针
    2.1 参数形式:void fun(vector<int>* p);
    2.2 函数调用:fun(&v);
    2.3 函数内使用:cout << (*p)[1];
    2.4 是否可以改变函数外对象的值:是
    2.5 是否会调用拷贝构造函数:
  3. const+传指针
    3.1 参数形式:void fun(const vector<int>* p);
    3.2 函数调用:fun(&v);
    3.3 函数内使用:cout << (*p)[1];
    3.4 是否可以改变函数外对象的值:否
    3.5 是否会调用拷贝构造函数:
  4. 传引用
    4.1 参数形式:void fun(vector<int>& v);
    4.2 函数调用:fun(v);
    4.3 函数内使用:cout << v[1];
    4.4 是否可以改变函数外对象的值:是
    4.5 是否会调用拷贝构造函数:
  5. const+传引用
    5.1 参数形式:void fun(const vector<int>& v);
    5.2 函数调用:fun(v);
    5.3 函数内使用:cout << v[1];
    5.4 是否可以改变函数外对象的值:否
    5.5 是否会调用拷贝构造函数:

结合代码对比

下面,我们来探讨,各种方式是否会修改到函数外部的v。
如果会,那我就把它定性为一种有风险的行为。如果不会,我就把它定性为一种安全的行为

一、传值

#include <iostream>
#include<vector>

void changeValue(std::vector<int> v) {
    //修改v里面的值
    v[0] = 2;
    std::cout << "修改值之后的第一个元素(函数内): " << v[0] << std::endl;
}
void changeReference(std::vector<int> v) {
    //修改v的指向
    std::vector<int> c;
    c.push_back(3);
    v = c;
    std::cout << "修改指向之后的第一个元素(函数内): " << v[0] << std::endl;
}


int main()
{
    std::vector<int> v;
    v.push_back(1);
    std::cout << "原本的第一个元素: " << v[0] << std::endl;
    changeValue(v);
    std::cout << "修改值后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReference(v);
    std::cout << "修改指向之后的第一个元素(函数外): " << v[0] << std::endl;
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言
可见,传值的话,如果在函数内修改了v的值或者指向,函数外的v也不会受到任何影响。因此是一种安全的行为。

二、传指针

#include <iostream>
#include<vector>

void changeValue(std::vector<int>* p) {
    //修改v里面的值
    (*p)[0] = 2;
    std::cout << "修改值之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}
void changeReferenced(std::vector<int>* p) {
    //修改v的指向的指向
    std::vector<int> c;
    c.push_back(3);
    p = &c;
    std::cout << "修改指向之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}
void changeReferencedReference(std::vector<int>* p) {
    //修改v的指向
    std::vector<int> c;
    c.push_back(3);
    *p = c;
    std::cout << "修改指向的对象的指向之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}


int main()
{
    std::vector<int> v;
    v.push_back(1);
    std::cout << "原本的第一个元素: " << v[0] << std::endl;
    changeValue(&v);
    std::cout << "修改值后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReferenced(&v);
    std::cout << "修改指向之后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReferencedReference(&v);
    std::cout << "修改指向的对象的指向之后的第一个元素(函数外): " << v[0] << std::endl;
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言

  • 由changeValue的结果可见,传指针的话,如果在函数内修改了p对应的元素的值,函数外的v会受到一样的影响;
  • 由changeReferenced的结果可见,如果在函数内修改了p的指向,则函数外的v不会受到任何影响,因为此时的p已经不再关联外部的v了
  • 然而,由changeReferencedReference的结果可见,如果不是修改p的指向,而是修改了p指向的对象的指向,那么结果就会相反,此时函数外的v也会受到一样影响!
  • 所有,传递指针,是有影响到外部的v的风险的,是一种有风险的行为

三、const+传指针

#include <iostream>
#include<vector>

void changeValue(const std::vector<int>* p) {
    //修改v里面的值
    (*p)[0] = 2;
    std::cout << "修改值之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}
void changeReferenced(const std::vector<int>* p) {
    //修改v的指向
    std::vector<int> c;
    c.push_back(3);
    p = &c;
    std::cout << "修改指向之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}
void changeReferencedReference(const std::vector<int>* p) {
    //修改v的指向的指向
    std::vector<int> c;
    c.push_back(3);
    *p = c;
    std::cout << "修改指向的对象的指向之后的第一个元素(函数内): " << (*p)[0] << std::endl;
}


int main()
{
    std::vector<int> v;
    v.push_back(1);
    std::cout << "原本的第一个元素: " << v[0] << std::endl;
    changeValue(&v);
    std::cout << "修改值后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReferenced(&v);
    std::cout << "修改指向之后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReferencedReference(&v);
    std::cout << "修改指向的对象的指向之后的第一个元素(函数外): " << v[0] << std::endl;
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言

  • 由图可知,我们无法修改p指向的容器的值,也无法修改p指向的容器的指向,因此这两种情况都不会导致外部的v被改变。
  • 但是,我们此时可以修改p的指向,那么我们有没有可能改变函数外的v呢。由上一条实验三我们知道,修改了p的指向之后,并不会影响到外部的v,因为此时p已经脱离了和v的关联了。所以修改p的指向,是不会影响到外部的v的风险的。
  • 综上,const+传指针的方式,是不会影响到外部的v的,是一种安全的行为

四、传引用

#include <iostream>
#include<vector>

void changeValue(std::vector<int>& v) {
    //修改v里面的值
    v[0] = 2;
    std::cout << "修改值之后的第一个元素(函数内): " << v[0] << std::endl;
}
void changeReference(std::vector<int>& v) {
    //修改v的指向
    std::vector<int> c;
    c.push_back(3);
    v = c;
    std::cout << "修改指向之后的第一个元素(函数内): " << v[0] << std::endl;
}


int main()
{
    std::vector<int> v;
    v.push_back(1);
    std::cout << "原本的第一个元素: " << v[0] << std::endl;
    changeValue(v);
    std::cout << "修改值后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReference(v);
    std::cout << "修改指向之后的第一个元素(函数外): " << v[0] << std::endl;
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言
可见,传引用的话,如果在函数内修改了v的值或者指向,函数外的v也会受到一样的影响。因此是一种有风险的行为

五、const+传引用

#include <iostream>
#include<vector>

void changeValue(const std::vector<int>& v) {
    //修改v里面的值
    v[0] = 2;
    std::cout << "修改值之后的第一个元素(函数内): " << v[0] << std::endl;
}
void changeReference(const std::vector<int>& v) {
    //修改v的指向
    std::vector<int> c;
    c.push_back(3);
    v = c;
    std::cout << "修改指向之后的第一个元素(函数内): " << v[0] << std::endl;
}


int main()
{
    std::vector<int> v;
    v.push_back(1);
    std::cout << "原本的第一个元素: " << v[0] << std::endl;
    changeValue(v);
    std::cout << "修改值后的第一个元素(函数外): " << v[0] << std::endl;
    v[0] = 1;
    std::cout << "\n原本的第一个元素: " << v[0] << std::endl;
    changeReference(v);
    std::cout << "修改指向之后的第一个元素(函数外): " << v[0] << std::endl;
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言
如图,由于const,我们无法修改v的元素的值,也无法修改v的指向。所以我们不会改变到函数外的v。也是一种安全的行为

总结
如果我们想要安全(不修改函数外的v的值),只有以下三种方式:

  1. 传值
  2. const+传指针
  3. const+传引用。
  • 这几种方法中,如果从是否调用拷贝构造函数的角度考虑,应该选择 const+指针 ,或者const+引用因为他们是不调用拷贝构造函数的
  • 但是如果从书写的方便性来说,应该选择 传值const+传引用 这两种方式,他们比const+传指针要更加便于书写,因为这两者只需要用v就可以代表传进来的vector对象,而const+传指针需要用(*p)的方式来代表,多了一个*,而且有时候还要加括号(),防止优先级有问题,比如要用[ ]取值的时候,必须写成类似(*p)[0],而不能是*p[0]这样的。
  • 实际使用中,似乎更多人用 const+传引用

const+引用是否调用拷贝构造函数

文章 C++(笔记)容器(vector)作为函数参数如何传参 中却认为,const+传引用调用拷贝构造函数。我认为这应该是错误的。因为大多数其他的文章都认为, const+传引用不会调用拷贝构造函数**。如 C++拷贝构造函数(复制构造函数)详解、C++ 中的 const & (常引用)参数 、C++ 基础之 “引用形参” 和 “利用const引用避免复制” & 等等。所以还是服从多数,const+引用不会调用拷贝构造函数。这也是它相比于直接传值的重要优势。


不调用拷贝构造函数的好处

具体可以学习C++拷贝构造函数(复制构造函数)详解这一篇文章。
我总结一下,好处可能有两个:

  1. 可以减少空间开销。
  2. 可以避免在类中定义了一个不好的拷贝构造函数,从而导致了形参和实参不一致。

补充:使用 const+引用/指针 比单独使用 引用/指针 作为参数的好处

  1. 更加安全。这一点毋庸置疑。加了const以后,不管是指针还是引用都不用担心更改到外部的对象的内容。
  2. 使得函数可以接受常量对象作为参数。除此之外,还有一个很重要的,就是,哪怕你在函数内仔细控制,保证不会修改引用/指针指向的外部对象,也建议加一个const。那是因为,这样就可以向函数传递常量对象,而直接使用 引用/指针 作为参数的话,是无法向函数传递常量对象的。(这里我还是参考了C++拷贝构造函数(复制构造函数)详解这篇文章,虽然文章里只是对拷贝构造函数的参数写法进行的建议,但是我认为道理其实是通用的)

如下,如果我使用 vector<int>& v作为参数(没有加const),那么我是无法传递一个常量vector对象进去的。
【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言
然而,如果我使用了 const vector<int>& v作为参数(加了const),我就可以传递一个常量vector对象。

#include <iostream>
#include<vector>

void printValue(const std::vector<int>& v) {
    std::cout << v[0];
}

int main()
{
    const std::vector<int> v = { 1, 2, 3 };
    printValue(v);
}

【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例),c++,开发语言
可以接受常量对象的话,整个函数的可用性会更加强。

参考链接

C++拷贝构造函数(复制构造函数)详解
C++中vector作为参数的三种传参方式(传值 && 传引用 && 传指针)
C++ 中的 const & (常引用)参数
C++ 基础之 “引用形参” 和 “利用const引用避免复制” &
C++(笔记)容器(vector)作为函数参数如何传参 (疑似有误)文章来源地址https://www.toymoban.com/news/detail-606414.html

到了这里,关于【C++】容器对象作为函数参数传递时,如何保证外部容器对象不被修改(以vector为例)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • @RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)

    目录 一、@RequestMapping  路由映射 二、参数传递 1、传递单个参数 2、传递多个参数 3、传递对象 4、后端参数重命名 5、传递数组 6、传递集合 7、传递JSON 8、获取url中的参数 9、上传图片/文件 指定请求访问的路径 既可以修饰类,又可以修饰方法 @RequestMapping支持Get、Post、Dele

    2024年02月04日
    浏览(52)
  • 接口测试系列(二)Postman如何传递list、map对象等参数

    请求参数一般为简单文本text,包含基本数据类型,如数字和字符串,填写在Params页签下。发送请求时,将自动加在地址栏后方。 基本数据类型,只需要将相应的值填写在对应的value区域即可。内容类型需选择x-www-form-urlencoded。 内容类型需选择form-data,在key区域,需选择File类型

    2024年02月05日
    浏览(46)
  • C语言如何传递参数到函数,并从函数中返回值?

    假设我们现在要写一个函数,名字叫做\\\"吃饭\\\"。这个函数的功能是传入参数\\\"食物\\\",然后从函数中返回一个值\\\"满足程度\\\"。我们来看看如何实现吧! 我们需要写一个函数原型,声明这个函数的存在和参数的类型。嗯,函数原型就像餐厅的菜单,告诉顾客有哪些选择和怎么点菜。

    2024年02月12日
    浏览(41)
  • Simulink中传递函数transfer fcn中迟滞参数如何设置

    小编希望借助simulink中的transfer fcn传递函数对突变的信号进行平滑的处理,后来发现对于transfer fcn中分母上的一个参数直接相关,模型如下: 然后模型采用定步长运行,运行步长0.001s,运行总时长15s。  运行结果如下: 随着分母中s项前的系数越小,处理后的信号越接近原始

    2024年02月11日
    浏览(37)
  • golang slice 作为参数值传递情况说明

    golang 中引用类型有:slice、map、interface、channel golang所有类型在函数中都是值传递,这个跟上面golang中有的数据类型为引用类型并不冲突,用下面四个slice实例帮助理解 说明: main 函数中slice[0]说明 fn 函数里面的修改,也改变函数外的值,这跟slice为引用类型的缘故 说明:s

    2024年02月15日
    浏览(41)
  • 如何将没有复制或移动构造函数的对象放入vector容器

    直接说答案,这个问题无法实现。原因是因为std::vector容器的插入一定会调用类对象的构造函数或者移动构造函数。 说一下为什么会有这个问题,因为不想用指针,我想直接通过类对象本身的RAII机制来实现的资源的控制,智能指针是一个解决方案,不过智能指针是写起来很繁

    2024年02月08日
    浏览(41)
  • C++ remove_if函数(遍历元素,将满足条件的元素移动到容器的末尾)(C++一元函数对象)(括号运算符operator())

    C++ 中的 remove_if 函数是用于从容器中删除满足指定条件的元素的算法。它定义在头文件 algorithm 中,函数签名如下: 其中: first 和 last 分别表示容器中要处理的元素的范围,其中 first 指向第一个要处理的元素,last 指向最后一个要处理的元素的下一个位置。这个范围应该是左

    2024年02月14日
    浏览(36)
  • postman同时传递文件和对象参数

     对象属性  BaseInfoReqDTO BaseInfo  postman测试 { \\\"baseInfo\\\": { \\\"funcFlag\\\": \\\"ZT066\\\", \\\"transNo\\\": \\\"201208021201010001\\\", \\\"transrDate\\\": \\\"2012-08-17\\\", \\\"transrTime\\\": \\\"13:43:40\\\", \\\"operator\\\": \\\"C\\\", \\\"fromSys\\\": \\\"1\\\", \\\"toSys\\\": \\\"1\\\", \\\"sourceId\\\": \\\"1\\\" }, \\\"taskCode\\\": \\\"123456789\\\", \\\"isReinsuredLetters\\\": \\\"N\\\", \\\"reinsuredResult\\\": \\\"1\\\", \\\"isReinsured\\\": \\\"Y\\\" } @RequestPart和@

    2024年02月06日
    浏览(41)
  • 【C++】STL 算法 - for_each 遍历算法 ( for_each 函数原型 | for_each 函数源码分析 | for_each 函数 _Fn _Func 参数 值传递说明 )

    在 C++ 语言 的 标准模板库 ( STL , Standard Template Library ) 中 , 提供了 for_each 算法 用于 对一个 STL 容器中的每个元素执行某个指定的 \\\" 操作 \\\" ; for_each 算法 中 执行的 \\\" 操作 \\\" 可以是一个 函数 / 函数对象 / Lambda 表达式 ; 在 for_each 函数 中 可以修改 被遍历的元素 , 也可以 不修改

    2024年01月17日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包