智能指针系列

Boost中提供的5类智能指针。分别是:

l        scoped_ptr           独占的指针

l        scoped_array       独占的数组

l        shared_ptr            引用计数指针

l        shared_array         引用计数数组

l        weak_ptr             shared_ptr的一个弱指针(不参与引用计数)

l        intrusive_ptr         自定义的引用计数指针

scoped_ptr和scoped_array

对于scoped_ptr和scoped_array是不可以拷贝构造和赋值的(拷贝构造函数和operator=都是私有成员)。所以它们不像auto_ptr那样传递指针的拥有权,而是独占拥有权,直至对象的销毁(当scoped_ptr和scropted_array析构的时候,所指向的对象也会被析构)。

构造:

scoped_ptr<int> a(new int);

scoped_ptr<int> b;

scoped_array<int> c(new int[100]);

scoped_array<int> d;

scoped_ptr使用new T或者是NULL来初始化对象。scoped_array使用new T[]或者NULL来初始化对象。

它们的默认构造函数,是使用NULL来初始化。

访问:

scoped_ptr重载了operator*和operator->操作符,而scoped_array重载了operator[]下标运算符。通过这几个操作符来操作它们所指向的对象。它们都可以通过T* get()成员函数得到原始的指针。

例如:

scoped_array<char> str(new char[100]);

strcpy(str.get(),"hello");

cout<<str[0]<<str[4]<<endl;//输出ho

void reset(T * p = 0)

reset用于重置指针指向的对象,当调用reset的时候scoped_ptr或scoped_array会先删除原来指向的对象(如果不是指向NULL的话)。reset的参数和它们构造函数的要求是一样的,必须是new T(或new T[])或者是NULL。

swap

swap全局函数和swap成员函数,交换两个智能指针指向的对象。例如:

scoped_ptr<int> a(new int);//a指向一个int

scoped_ptr<int> b;//b指向NULL

swap(a,b);//这时,a指向NULL,b指向一个int

bool

scoped_ptr和scoped_array可以隐式的转换为bool类型,当指向NULL的时候返回false,否则返回true。

类型

scoped_ptr<T>和scoped_array<T>中的类型T不能是void类型。

并且scoped_ptr<T>和scoped_ptr<U>不存在类型转换,即使T和U是可以转换的,scoped_ptr<T>和scoped_ptr<const T>也不能转换。

shared_ptr和shared_array

shared_ptr和shared_array是引用计数的智能指针。

下面仅仅介绍shared_ptr的使用。。。剩余内容参考 http://hi.baidu.com/vicehunter/blog/item/ab6d7300ea1cfb0f1c958370.html


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

boost::scoped_ptrstd::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放。下列代码演示了该指针的基本应用:

#include <string>
#include <iostream>
#include <boost/scoped_ptr.hpp>

class implementation
{
public:
    ~implementation() { std::cout <<"destroying implementation\n"; }
    void do_something() { std::cout << "did something\n"; }
};

void test()
{
    boost::scoped_ptr<implementation> impl(new implementation());
    impl->do_something();
}

void main()
{
    std::cout<<"Test Begin ... \n";
    test();
    std::cout<<"Test End.\n";
}

 

该代码的输出结果是:

Test Begin ...
did something
destroying implementation
Test End.

可以看到:当implementation类离其开impl作用域的时候,会被自动删除,这样就会避免由于忘记手动调用delete而造成内存泄漏了。

boost::scoped_ptr特点:

boost::scoped_ptr的实现和std::auto_ptr非常类似,都是利用了一个栈上的对象去管理一个堆上的对象,从而使得堆上的对象随着栈上的对象销毁时自动删除。不同的是,boost::scoped_ptr有着更严格的使用限制——不能拷贝。这就意味着:boost::scoped_ptr指针是不能转换其所有权的。

  1. 不能转换所有权
    boost::scoped_ptr所管理的对象生命周期仅仅局限于一个区间(该指针所在的"{}"之间),无法传到区间之外,这就意味着boost::scoped_ptr对象是不能作为函数的返回值的(std::auto_ptr可以)。
  2. 不能共享所有权
    这点和std::auto_ptr类似。这个特点一方面使得该指针简单易用。另一方面也造成了功能的薄弱——不能用于stl的容器中。
  3. 不能用于管理数组对象
    由于boost::scoped_ptr是通过 delete来删除所管理对象的,而数组对象必须通过 deletep[]来删除,因此boost::scoped_ptr是不能管理数组对象的,如果要管理数组对象需要使用boost::scoped_array类。

boost::scoped_ptr的常用操作:

可以简化为如下形式:

namespace boost {

    template<typename T> class scoped_ptr : noncopyable {
    public:
        explicit scoped_ptr(T* p = 0); 
        ~scoped_ptr(); 

        void reset(T* p = 0); 

        T& operator*() const
        T* operator->() const
        T* get() const

        void swap(scoped_ptr& b); 
    };

    template<typename T> 
    void swap(scoped_ptr<T> & a, scoped_ptr<T> & b); 
}

 

它的常用操作如下:

成员函数

功能

operator*()

以引用的形式访问所管理的对象的成员

operator->()

以指针的形式访问所管理的对象的成员

get()

释放所管理的对象,管理另外一个对象

swap(scoped_ptr& b)

交换两个boost::scoped_ptr管理的对象

 

boost::scoped_ptr和std::auto_ptr的选取:

boost::scoped_ptr和std::auto_ptr的功能和操作都非常类似,如何在他们之间选取取决于是否需要转移所管理的对象的所有权(如是否需要作为函数的返回值)如果没有这个需要的话,大可以使用boost::scoped_ptr,让编译器来进行更严格的检查,来发现一些不正确的赋值操作。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

auto_ptr 和 scoped_ptr比较和区别,深入理解

分类: boost    1589人阅读 评论(0) 收藏 举报

#include "boost/scoped_ptr.hpp"
#include <iostream>
#include <memory>//contain auto_ptr 
using namespace std;
using  boost::scoped_ptr;

int main(int argc, char* argv[])
{

 scoped_ptr<int > sp( new int(10) ) , sp2;
 //sp = new int(10)
 //error,因为拷贝构造函数和赋值构造函数都是私有的
 //
 cout<< *sp<<endl;

//sp2=sp;  //error
 int *p=sp.get(); //不会导致sp失去空间的占有权
 //delete p ;//将导致错误,因为sp是分配的空间的所有者,只有它才有权利进行释放
 *p = 20;
 cout<< *sp<<endl;
 
 auto_ptr<int> ap(new int(1)) ,ap2;
 //ap = new int(1); //error
 ap2 = ap ; //ap将失去分配的空间的所有权
 int *p2 = ap2.get();//不会导致ap2失去空间的占有权
 *p2=100;
 //delete p2 ;//将导致错误,因为ap2是分配的空间的所有者,只有它才有权利进行释放
 return 0;
}

/////////////////////////////////////////////////////

智能指针类其实包含有几个数据成员其中一个就是所有权标记,另外一个就是指向动态分配的空间的地址。

1.只有对这个动态分配的空间拥有所有权的指针或者智能指针对象才有权利去释放这个空间。

因为如果使用指针的话没有所有权保护,所以虽然原则上是拥有所有权的才能释放但是如果是使用指针 就没办法确定一个指针是否占有所有权。所以不建议这么做。

//所有权与使用权分离。有使用权不一定有所有权!

另外智能指针类可以通过构造函数的访问属性和参数特性来禁止某些操作或允许某些操作。比如把重载赋值为私有来禁止赋值,把拷贝构造函数设置为私有来禁止拷贝。

2.对于智能指针而言get操作智能取得动态分配的空间的地址。而不能使智能指针失去所有权

3.一个动态分配的空间在只有一个所有权并且在某一个只能有一个所有者。但可以有多个使用者。

使用者可以对空间的内容进行赋值,但不允许进行释放操作。

auto_ptr代表的动态分配的空间的所有权是可以转移( 通过赋值)的。

scoped_ptr代表的动态分配的空间的所有权则不能转移(重载赋值为私有来禁止赋值,把拷贝构造函数设置为私有来禁止拷贝。)!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Solmyr 的小品文系列之五:垃圾收集    什么是智能指针


<think>我们正在处理用户的问题:用户想定义一系列智能指针相关的宏,用于创建智能指针别名。 根据引用[5]中提到的宏定义和typedef的区别,我们知道宏定义是简单的文本替换,而typedef是定义类型别名。 在C++中,通常我们更推荐使用typedef或using来定义类型别名,因为宏定义可能会带来一些意想不到的问题(比如作用域、优先级等)。 然而,用户特别提到了要使用宏定义(#define)来创建智能指针别名,所以我们需要按照用户的要求来。 智能指针在C++中主要有:std::unique_ptr, std::shared_ptr, std::weak_ptr等。 用户可能希望有这样的宏: #define MY_PTR(type) std::shared_ptr<type> 然后就可以使用 MY_PTR(int) 来代表 std::shared_ptr<int> 但是,注意宏定义只是简单的替换,所以上面的定义是可行的。 然而,引用[5]中提到了一个关键区别:宏定义在定义多个变量时可能会出现问题。例如: #define pChar char* pChar c1, c2; // 实际是 char *c1, c2; 即c1是指针,c2是char 为了避免这个问题,我们通常会在宏定义中加入括号,例如: #define pChar (char*) pChar c1, c2; // 现在变成 (char*) c1, c2; 这仍然不对,因为c2还是char类型 所以,用宏定义类型别名来声明多个变量是有问题的。因此,我们通常不建议用宏来定义类型别名。 但是,如果用户坚持要用宏,并且只用于单个类型别名的场景(比如只声明一个变量,或者用于函数参数、模板参数等),那么可以定义。 另外,智能指针别名通常用于简化复杂类型的书写,比如: std::shared_ptr<std::vector<std::string>> 可以用一个宏来简化。 考虑到用户要求,我们可以这样定义: #define SHARED_PTR(type) std::shared_ptr<type> #define UNIQUE_PTR(type) std::unique_ptr<type> #define WEAK_PTR(type) std::weak_ptr<type> 但是,如果用户需要定义多个智能指针类型,比如同时定义两个shared_ptr,那么用宏就会有问题: SHARED_PTR(int) p1, p2; // 会被替换成 std::shared_ptr<int> p1, p2; 这里p2是int类型,不是智能指针! 所以,为了避免这个问题,我们可以使用typedef或using,但用户要求用宏。 另一种方法是定义宏为整个类型,包括后面的变量名,但这显然不灵活。 因此,我们需要提醒用户,使用宏定义类型别名时,每个变量必须单独声明。 或者,我们可以定义宏为包含括号的形式,例如: #define SHARED_PTR(type, var) std::shared_ptr<type> var // 然后使用 SHARED_PTR(int, p1); 这样声明一个变量 但是这样用起来比较繁琐,而且不能用于函数返回类型等地方。 考虑到用户的需求是“创建智能指针别名”,实际上更合适的做法是使用using: template<typename T> using SharedPtr = std::shared_ptr<T>; 然后就可以用 SharedPtr<int> 来声明变量,而且可以同时声明多个:SharedPtr<int> p1, p2; 都是智能指针。 但是用户明确要求用宏,所以我们还是提供宏的版本,并指出其局限性。 因此,我们可以这样回答: 回答: 在C++中,您可以使用宏定义来为智能指针创建别名,但需要注意宏是简单的文本替换,可能会在声明多个变量时产生问题。以下是一些示例: 1. 基本定义: ```cpp #include <memory> #define SHARED_PTR(type) std::shared_ptr<type> #define UNIQUE_PTR(type) std::unique_ptr<type> #define WEAK_PTR(type) std::weak_ptr<type> ``` 使用示例: ```cpp SHARED_PTR(int) pInt = std::make_shared<int>(42); UNIQUE_PTR(double) pDouble = std::make_unique<double>(3.14); ``` 2. 注意:当需要声明多个变量时,每个变量必须单独使用宏(因为宏替换后,逗号会分隔变量,导致只有第一个变量是指针类型): ```cpp // 错误示例:会导致p2是int类型,而不是shared_ptr<int> SHARED_PTR(int) p1, p2; // 正确做法:分别声明 SHARED_PTR(int) p1; SHARED_PTR(int) p2; ``` 3. 如果需要同时声明多个智能指针变量,建议使用typedef或using(C++11起): ```cpp template<typename T> using SharedPtr = std::shared_ptr<T>; // 然后可以 SharedPtr<int> p1, p2; // 都是shared_ptr<int> ``` 4. 如果坚持使用宏且希望一次声明多个变量,可以定义包含多个变量的宏(但不推荐,因为这样不灵活): ```cpp #define SHARED_PTR2(type, var1, var2) std::shared_ptr<type> var1; std::shared_ptr<type> var2 // 使用 SHARED_PTR2(int, p1, p2); ``` 5. 另外,对于模板参数较多的智能指针,比如智能指针指向一个容器,宏定义可以简化书写: ```cpp #define SHARED_VECTOR(type) std::shared_ptr<std::vector<type>> // 使用 SHARED_VECTOR(int) pVec = std::make_shared<std::vector<int>>(); ``` 总结:虽然宏可以实现,但存在局限性,特别是声明多个变量时。在C++中,更推荐使用`using`来定义类型别名,这样更安全且符合作用域规则。 根据引用[5]的示例,宏定义在类型别名上的使用需要谨慎,因为宏不遵守作用域规则,且可能导致难以发现的错误。 因此,建议在可能的情况下优先使用`using`别名。 相关问题: 1. 宏定义和typedef/using在定义类型别名时的主要区别是什么? 2. 在C++中,如何为模板类型创建别名? 3. 智能指针的使用有哪些注意事项?</think>### 在C++中使用宏定义创建智能指针别名 在C++中,可以使用宏定义创建智能指针别名,但需注意宏的文本替换特性可能导致的陷阱。以下是具体实现方法和注意事项: #### 1. 基本宏定义实现 ```cpp #include <memory> // 为shared_ptr创建别名宏 #define SHARED_PTR(type) std::shared_ptr<type> // 为unique_ptr创建别名宏 #define UNIQUE_PTR(type) std::unique_ptr<type> // 使用示例 int main() { SHARED_PTR(int) p1 = std::make_shared<int>(42); // 等价于 std::shared_ptr<int> UNIQUE_PTR(double) p2 = std::make_unique<double>(3.14); // 等价于 std::unique_ptr<double> } ``` #### 2. 处理指针类型组合(如指针的指针) ```cpp // 正确做法:使用括号确保类型完整性 #define SHARED_PTR_TO_PTR(type) std::shared_ptr<type*> // 错误示例:不加括号会导致语法错误 #define UNSAFE_PTR_MACRO(type) std::shared_ptr<type*> // 可能导致替换问题 // 使用示例 SHARED_PTR_TO_PTR(int) pp = std::make_shared<int*>(new int(10)); ``` #### 3. 重要注意事项 1. **作用域限制**:宏不受命名空间和类作用域约束,全局生效 ```cpp namespace MyApp { #define APP_PTR(type) std::shared_ptr<type> // 宏会泄漏到全局 } ``` 2. **类型安全风险**:宏不做类型检查,可能导致意外替换 ```cpp #define PTR_ALIAS(type) std::shared_ptr<type> PTR_ALIAS(std::string) strPtr; // 正确 PTR_ALIAS(int*) ptrPtr; // 实际生成 std::shared_ptr<int*> ``` 3. **优先推荐替代方案**(C++11起): ```cpp // 使用using更安全 template<typename T> using SafeSharedPtr = std::shared_ptr<T>; SafeSharedPtr<int> p = std::make_shared<int>(10); // 类型安全且支持模板 ``` #### 4. 实际应用场景示例 ```cpp // 定义智能指针别名宏 #define CONFIG_PTR(type) std::shared_ptr<type> #define SENSOR_PTR(type) std::unique_ptr<type> struct Config { /*...*/ }; struct Sensor { /*...*/ }; int main() { CONFIG_PTR(Config) config = std::make_shared<Config>(); SENSOR_PTR(Sensor) sensor = std::make_unique<Sensor>(); } ``` ### 关键区别(宏 vs using) | 特性 | 宏定义 (#define) | using别名 | |--------------------|--------------------------|------------------------| | **类型检查** | ❌ 无 | ✅ 有 | | **作用域** | ❌ 全局替换 | ✅ 遵守命名空间规则 | | **模板支持** | ⚠️ 有限支持 | ✅ 完整支持 | | **调试信息** | ❌ 不可见 | ✅ 保留类型信息 | | **多标识符声明** | ❌ 易出错(参考[^5]) | ✅ 安全 | > 虽然宏能实现智能指针别名,但在现代C++中**强烈推荐使用`using`**,因为它提供更好的类型安全性和作用域控制。宏定义应仅用于遗留代码维护或特定元编程场景[^3][^5]。 --- ### 相关问题 1. 宏定义和`using`在定义类型别名时的主要性能差异是什么? 2. 如何为带有自定义删除器的智能指针创建类型别名? 3. 在模板编程中,哪种类型别名方案更适合元编程? 4. 宏定义的类型别名在跨平台开发中可能遇到哪些兼容性问题? 5. 智能指针的类型别名如何影响C++的移动语义和完美转发? > 参考资料: > [^1]: 宏定义在预处理阶段进行简单文本替换 > [^3]: `#define`无视C++语法限制,可能引发意外替换 > [^5]: 宏定义类型别名在声明多个变量时可能产生歧义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值