首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

共享指针的赋值/初始化差异

共享指针(shared_ptr)是C++标准库中的一种智能指针,用于管理动态分配的对象的生命周期。它通过引用计数机制来跟踪有多少个共享指针指向同一个对象,并在最后一个共享指针被销毁时自动释放对象。

共享指针的赋值与初始化差异

初始化

共享指针的初始化通常发生在创建共享指针对象时。有以下几种常见的初始化方式:

  1. 默认初始化
  2. 默认初始化
  3. 使用new表达式初始化
  4. 使用new表达式初始化
  5. 使用std::make_shared函数初始化(推荐):
  6. 使用std::make_shared函数初始化(推荐):
  7. 从另一个共享指针初始化
  8. 从另一个共享指针初始化

赋值

赋值操作发生在已经存在的共享指针对象之间。赋值操作会改变指针的指向,并相应地更新引用计数。

  1. 赋值给另一个共享指针
  2. 赋值给另一个共享指针
  3. 赋值为新的对象
  4. 赋值为新的对象

差异总结

  • 初始化是在创建共享指针对象时进行的,决定了指针最初指向的对象。
  • 赋值是在已有共享指针对象之间进行的,改变了指针的指向,并可能影响对象的生命周期管理。

优势与应用场景

  • 自动内存管理:通过引用计数自动释放内存,减少内存泄漏的风险。
  • 共享所有权:允许多个指针共享同一个对象的所有权,适用于需要在多个部分之间传递和管理同一资源的场景。
  • 线程安全:标准库中的std::shared_ptr提供了基本的线程安全保证,适合多线程环境使用。

可能遇到的问题及解决方法

  1. 循环引用:两个或多个共享指针相互引用,导致对象永远不会被释放。
    • 解决方法:使用std::weak_ptr打破循环引用。
  • 性能问题:频繁的引用计数操作可能影响性能。
    • 优化方法:尽量减少不必要的共享指针操作,或使用std::make_shared一次性分配内存。
  • 误用裸指针:直接使用裸指针初始化或赋值共享指针可能导致资源管理混乱。
    • 预防措施:始终使用std::make_shared或确保裸指针的正确所有权转移。

通过理解这些基础概念和操作差异,可以更有效地使用共享指针来管理动态资源,避免常见的内存管理问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C语言指针的初始化和赋值

1、指针的初始化 指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是int*p=0;除外,该语句表示指针为空)。...因为p是指向7所在的地址,*p = 7给p所指向的内存赋值,p没有赋值,所以p所指向的内存位置是随机的,没有初始化的。...p1 = p2; //注意啦,p1指向了val2,而没有指向val1 备注:字符串与指针的初始化和赋值 初始化: char *cp = “abcdefg”; //这个初始化过程,是将指针cp指向字符串的首地址...,如:char *cp = “abcdefg”; 对指针进行初始化或赋值的实质是将一个地址或同类型(或相兼容的类型)的指针赋给它,而不管这个地址是怎么取得的。...6、指向指针的指针 在指针初始化的第5种方式中提到了用一个指针的地址来初始化一个指针。回忆一下上一讲的内容:指针是一种变量,它也有自己的地址,所以它本身也是可用指针指向的对象。

2.6K10

【编程基础】C语言指针的初始化和赋值

1、指针的初始化 指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是int*p=0;除外,该语句表示指针为空)。...因为p是指向7所在的地址,*p = 7给p所指向的内存赋值,p没有赋值,所以p所指向的内存位置是随机的,没有初始化的。...p1 = p2; //注意啦,p1指向了val2,而没有指向val1 备注:字符串与指针的初始化和赋值 初始化: char *cp = "abcdefg"; //这个初始化过程,是将指针cp指向字符串的首地址...,如:char *cp = “abcdefg”; 对指针进行初始化或赋值的实质是将一个地址或同类型(或相兼容的类型)的指针赋给它,而不管这个地址是怎么取得的。...6、指向指针的指针 在指针初始化的第5种方式中提到了用一个指针的地址来初始化一个指针。回忆一下上一讲的内容:指针是一种变量,它也有自己的地址,所以它本身也是可用指针指向的对象。

3.3K80
  • 【C 语言】指针间接赋值 ( 指针作为 函数参数 的意义 | 间接赋值 代码示例 )

    文章目录 一、指针作为 函数参数 ( 间接赋值 ) 的意义 二、间接赋值 代码示例 一、指针作为 函数参数 ( 间接赋值 ) 的意义 ---- 调用函数时 , 调用 & 取地址 生成 实参 p , 将...指针变量 p 实参 传递给 函数形参 , 在函数中 借助传入的 指针 可以 实现 与 外部函数 的内存共享 , 在函数中使用 *p 修改内存值 , 可以将 运算结果通过 *p 传递出来 ; 指针 作为...函数参数 , 可以实现 主函数 与 被调用子函数 之间 内存交换 ; 下面是逻辑链 : 指针作函数参数 ( 间接赋值 ) -> 接口封装与设计 -> 模块划分 -> 软件分层 正是因为有了 间接赋值 ,...才能实现 接口封装与设计 , 进而实现了 模块划分 , 最后实现了 软件分层 ; 使用 指针 ( 一级指针 或 多级指针 ) 作为参数 , 可以更加灵活的在 函数中 对 传入的 指针 指向的内存数据...进行处理 , 这些修改 , 可以保留到函数值返回之后 , 这些参数都可以作为返回值使用 ; 使用 指针 ( 一级指针 或 多级指针 ) 作为参数 , 实现了 main 函数 , 与 其它 子函数 之间的

    1.2K10

    深拷贝浅拷贝和赋值的差异

    区别 浅拷贝---拷贝的是一个对象的指针,而不是复制对象本身,拷贝出来的对象共用一个指针,其中一个改变了值,其他的也会同时改变。...深拷贝---拷贝出来一个新的对象,开辟一块新的空间,拷贝前后的对象相互独立,互相不会改变,拥有不同的指针。...,赋值对于基本数据来说就是在栈中新开了一个变量,相当于是两个独立的栈内存,所以相互不会影响,但是对于引用数据类型,他只是复制了一份a在栈内存的指针,所以两个指针指向了同一个堆内存的空间,通过任何一个指针改变值都会影响其他的...,通过这样的赋值可以产生多个指针,但是堆内存的空间始终只有一个,这就是赋值产生的问题,我们在开发中当然不希望改变B而影响了A,所以这个时候就需要用到浅拷贝和深拷贝了。...针对基本数据类型,随便赋值都不会相互影响 针对引用数据类型,赋值就会出现我们不想看到的,改动一方双方都变化。

    46520

    关于golang中指针赋值的问题

    最近在SO上找到了一个很有意思的问题: 这个问题是关于一个指针在外部函数的赋值,当然,解决方法也很简单。...如果是学过C风格指针的话应该会发现这条语句是很奇怪的,从语法上讲u中存放的地址会被改变,但是实际上它并不会改变(PS:原来的这个代码需要修改一下,不然会有dereference nil的错误) 修改后的例子...0xc000006028, address inside pointer is 0xc000004580 main(): user IP address is 129.0.0.1 可以看到,对于主函数中的指针...问题在于,传入函数中的指针的地址是变动的,也就是传入函数的指针并不是原来的指针(这很正常,因为golang并没有引用传值,每一个变量的地址都是不一样的)。...所以,单纯修改指针中存放的内容是没有任何用处的。如果假设指针是杯子,里面存放的内容是某种液体,现在main函数中的u杯子里面装的是水,那么defaultIP杯子中装的就是酱油。

    99730

    const修饰的双重指针赋值解惑

    在c程序中,我们可能经常会使用到指针之间的赋值。...传统的赋值操作: char *cp = "c"; const char *ccp; ccp = cp; printf("*ccp:%c",*ccp); 会正常打印出*cpp所指的字符。...ccp是一个const修饰符修饰的指向char类型的指针,也就是说,它指向的是char类型,但是指针本身是不可修改的。...也就是说: ccp是一个指向有const修饰符的指针,cp是一个指向没有const修饰符的指针。ccp中包含了cp的所有修饰符(其实cp就没啥修饰符),因此可以进行赋值。...这样,我们看一下面的代码: c是一个指向char类型指针的指针。 cc是一个指向const修饰符修饰的char类型的指针的指针。 cc 与 c指向的内容并不相同,因此无法进行赋值操作。

    1K90

    c语言中指针赋值问题,关于C语言指针赋值的问题「建议收藏」

    大家好,又见面了,我是你们的朋友全栈君。 为方便各位小伙伴更好的学习C语言,武林技术小编为此给大家整理了一批资料,供大家交流学习,下面就跟随武林技术频道的编辑一起来先来看看关于C语言指针赋值的问题。...:22: 警告: 赋值时将指针赋给整数,未作类型转换 test.c:23: 警告: 赋值时将指针赋给整数,未作类型转换 test.c:24: 警告: 赋值时将指针赋给整数,未作类型转换 test.c:25...(uchar *)的强制类型转换是为了配合(uchar *p). ——————————————- 应该注意的2点是: 1.给指针只能传地址,不能传值.否则要做强制类型转换. 2.在做类型转换和赋值时候,...应该注意赋值的类型匹配....以上就是关于C语言指针赋值的问题,想必都已有了一定的了解,更多关于C语言的内容请继续关注武林技术频道。

    1.6K10

    类成员的初始化与赋值

    y = yy; } 其中,x 以构造函数特有的语法(初始化列表)的形式被初始化,而 y 则在构造函数中被赋值。...: 初始化发生的时机比赋值要早。...初始化发生的时刻实际上是程序刚刚开始运行的时候,而赋值语句则要等到程序执行到该语句才开始。 初始化的执行效率比赋值要高。...事实上,类的成员数据在构造函数中被赋值之前,已经被系统进行过一次 default 的初始化,因此赋值语句相当于抹掉了先前初始化的执行效果,使得系统做了一次无用功。...而在构造函数中运用初始化列表则可以避免这样的效率浪费。 常量成员(const)和引用成员(reference)只能使用初始化列表来赋值。

    1.1K20

    PLSQL 集合的初始化与赋值

    对于集合类型,与单一的数据类型相比较而言,应该以一个整体的观念来考虑集合,即是一批类型相同的数据组合而非单一的数据。因此集 合类型集合的声明、赋值、初始化较之单一类型而言,有很大的不同。...有关集合类型的描述请参考: PL/SQL 联合数组与嵌套表 PL/SQL 变长数组 PL/SQL --> PL/SQL记录 一、联合数组的赋值     联合数组的不需要初始化,直接赋值即可。...|| ') value is ' || loc_tab( v_counter ) ); END LOOP; END; 二、集合的初始化与赋值 1、初始化的方法      集合类型主要分为三步来完成...,使用构造函数直接初始化并赋值 -->变长数组的初始化与嵌套表一样,可以使用构造函数直接初始化并赋值 DECLARE TYPE varry_loc_type IS VARRAY( 10 ) OF...5、集合类型的赋值可以在声明块声明时赋值,也可以在执行块执行时使用extend方式扩展后再赋值。 6、集合类型的初始化过程连同赋值可以在声明集合的同时使用构造函数直接进行初始化并赋值,从而一步完成。

    2.3K50

    字符数组的初始化与赋值

    代码编译运行环境:VS2017+Win32+Debug ---- 1.字符数组的初始化方式 C语言中表示字符串有两种方式,数组和指针,字符数组是我们经常使用的方式。...变量的定义包括指明变量所属类型、变量名称、分配空间以及初始化。可以看出,变量的初始化是变量定义的一部分。...除了const变量需要显示初始化以外,其它变量如果在定义时未显示初始化,编译器会为变量以默认值进行初始化。变量的赋值和初始化有着本质的区别,字符数组也是如此,具体见我的另一篇博客:认识初始化。...test3[256]={'\0'}; 2.字符数组的赋值 当为已经完成定义的字符数组赋值时,不能采用类似于初始化的方式为字符数组赋值了。...左值的概念见博客:认识左值与常引用。 2.1逐个字符赋值 (1)for循环的方式。

    7.3K20

    es6的解构赋值_字符串赋值给字符指针

    大家好,又见面了,我是你们的朋友全栈君。...ES6 模板字符串与解构赋值 解构赋值 展开运算符 模板字符串 特点 模板字符串可以换行 模板字符串中变量表达方式 ${变量/表达式} //模板字符串 //特点...特点: 可以定义默认值 可以嵌套 可以不完全解构 好处: 不通过遍历,方便快捷的将元素取出来 //解构赋值 //可以定义默认值 //可以嵌套 //可以不完全解构...//数组用法 let a=[1,2,3] let [b,c,d]=a; console.log(b,c,d)//1,2,3 //数组解构赋值时可以嵌套 let s=[[1,2...一定要与对象的属性名一致,如果想不一致的话,要在变量的前面加属性名: console.log(name,age);//xiaoxiao 15 //错误写法 // let {fg

    2.3K20

    类成员初始化和赋值的内幕

    { b = bb; } private: int a; int b; }; 可以看到 a 的值是用初始化列表的方式进行初始化,而 b 的值是通过构造函数的参数进行赋值...在类对象调用构造函数的时候,以上两种方式都可以确保 a 和 b 的值是可以确定的,但是初始化和赋值两种方式是有区别的: 初始化发生的时机肯定比赋值早。...初始化会在程序刚开始运行的时候发生,而赋值是只有在程序执行到这条语句才会发生。 初始化的执行效率要比赋值高。...类成员在构造函数中执行的赋值语句之前已经被系统进行了初始化,当执行赋值的时候就需要抹掉之前default的初始化的数据,这样就相当于多做了一次无用功,而构造函数中运行的初始化列表则不需要做这次无用功。...另外,类成员的初始化的顺序的固定的:如果有基类的话,先初始化基类,然后按照类中声明的顺序去初始化派生类中的类成员。

    40720

    【C 语言】指针数据类型 ( 指针类型变量 与 指针指向的内存块 概念区别 | 指针赋值 | 指针运算 | 内存赋值 | 内存取值 | 内存修改注意事项 )

    文章目录 一、指针类型变量 与 指针指向的内存块 概念区别 1、指针赋值 2、指针运算 3、内存赋值 4、内存取值 5、内存修改注意事项 一、指针类型变量 与 指针指向的内存块 概念区别 ---- 指针类型变量...&a; 1、指针赋值 给指针赋值 : 给上述指针变量 p 赋值操作 , 如 p = 0x7F451D12 , 只改变指针变量 p 的值 , 没有改变指针变量 p 原来指向的 内存块 中存储的值 ; char..., p + 1 与 p++ 的计算结果是指针的地址值加上指针类型对应的字节大小值 , 如果是 int 类型的指针 , 则增加 4 字节 ; 3、内存赋值 ** 给指针指向的内存赋值 * 给上述指针变量...p 指向的内存 进行赋值操作 , 如 *p = 0x7F451D12 , 不会改变指针变量 p 的值 , 只会改变指针变量 p 原来指向的 内存块 中存储的值 ; 4、内存取值 指针指向的内存赋值与取值...: 给内存赋值 : *p 如果在 等号 = 左边 , 则表示给 指针 指向的 内存 赋值 ; 从内存取值 : *p 如果在 等号 = 右边 , 则表示从 指针 指向的 内存 取值 ; 5、内存修改注意事项

    3K20

    指向字符串的指针赋值就出错?

    现有一个指向字符串的指针, char *test ="123123123"; 如果执行下面这句话就会出错 *test=“321321”; 这是因为 test 这个指针指向的是123123123这个储存于常量区的字符串...这个区域的数据是不可改写的,所以运行*test=“321321”;这句话会出错。 数据存在于哪里通常可以用4个区来表达,也就是常说的内存四区。...通常说的内存四区指的就是上图中的堆区、栈区、全局区和代码区这四个部分,全局区又可以分为全局变量区和常量区。 栈区包括局部变量、函数的入参,返回值等。堆区是由程序员自行分配的内存。...为什么要划分这几个区呢,这是因为把不同的数据放到不同的区里,就赋予了这些变量或常量不同的生命周期和不同的释放方式,这样我们在编程中就可以根据需求灵活运用。...通过以上可以看出,上图中红色框内的是不可以更改的,开头那个字符串是存储在常量区的,是不可以更改的。所以开头的那个程序运行就会出错。

    52930

    【C 语言】指针间接赋值 ( 间接赋值三要素 | 间接赋值 使用的三种场景 )

    ; ② 实参地址赋值给形参 ; ③ 使用形参指针修改实参值 ; 间接赋值 3 大要素 : 要素 ① : 定义 实际变量 ( 实参 ) , 以及接收 实际变量 地址的 指针参数 ( 形参 ) ; 如果...: 使用 形参指针 修改 实际变量 ( 实参 ) 的值 ; *p = 20; 二、间接赋值 使用场景 ---- 上述 间接赋值 3 要素 , ① 定义实参和形参 ; ② 实参地址赋值给形参 ;...; ( 最常见 ) 语法现象 三 : ① 在一个函数中 , ② ③ 在另一个函数中 ; ( 初始化函数常用 ) 1、① ② ③ 都在同一个函数中 #include #include...0 char *p = NULL; // 将 a 的地址赋值给 指针变量 p p = &a; // 通过指针 简介修改 变量 a 的值 // * 符号可以看做..., 并为其设置 NULL 初始值 // NULL 就是 0 int *p = NULL; // 将 a 的地址赋值给 指针变量 p p = &a; // 调用

    1.9K20

    【Kotlin】类的初始化 ③ ( init 初始化块 | 初始化顺序 : 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码 )

    文章目录 一、init 初始化块 二、初始化顺序 一、init 初始化块 ---- 在 Kotlin 类中 , 可以定义 init 初始化块 , 在其中可以为 变量赋值 , 执行一些检查相关的代码 ,...时会执行一系列的 初始化操作 , 这些操作按照如下顺序执行 : 主构造函数 中属性赋值 类中的属性赋值 init 初始化块 中的代码执行 次构造函数 中的代码执行 代码示例 : 通过下面的代码分析 Kotlin..., 这是在 主构造函数 中完成的操作 ; 然后 , 为 age 和 type 属性赋值 , 这是在 类 中的 age 属性进行的赋值 , 使用的是 主构造函数 中的临时变量 ; 最后 , 为 gender...赋值 , 这是在 init 初始化块 中进行的赋值 ; 然后分析 次构造函数 , 在 如下的 次构造函数的代码中 , 先执行了 主构造函数 , 然后才为 type 属性赋值 , 这是在次构造函数中执行的...: 主构造函数属性赋值 -> 类属性赋值 -> init 初始化块代码 -> 次构造函数代码

    2.2K30

    vector初始化与否导致的巨大性能差异

    为了确认是否是因为CPU Cache而导致的性能差异,所以将测试分成两个独立的程序进行,即分别执行uninitialized_performance()和initialized_performance(...对于未初始化的vector,该vector申请了一大块内存,operator new只是返回了虚拟地址(此时并未将物理地址与其关联),当具体访问数据(for循环)的时候,操作系统才会将虚拟地址与物理地址进行关联...在源码一节中,我们提到未初始化版本和初始化版本最终分别调用了std::_Construct(std::__addressof(*__cur))和_Construct(std::__addressof(*...后面,对示例代码进行了修改: 1、在默认的构造函数中对变量进行了赋值初始化操作 AdItem() { x_ = 0; y_ = 0; z_ = 0; } 2、对构造函数使用default...关键字 AdItem() = default; 修改之后,再次编译,运行,未初始化版本和初始化版本的性能结果基本一致,进一步验证了我们的猜想lazy allocation引起的性能差异。

    74310
    领券