c++之指针

共享指针(std::shared_ptr)实现了共享指针的所有权—只要存在对它的有效引用,它们就使该对象保持活动状态,因为没有单个所有者。通常使用引用计数来完成,这意味着相对于唯一指针,它们具有额外的运行时开销。同样,关于共享所有权的推理比关于专有所有权的推理要困难得多-破坏点变得不确定性强。

#include <iostream>
#include <memory>
 
// shared_ptr顾名思义是多个指针指向一块内存。
// 被管理对象有一个引用计数,这个计数记录在每个指针上,几个shared_ptr指向它,这个数字就是几,当没有任何shared_ptr指向它时,引用计数为0,这时,自动释放对象。
// 其功能在于当所有指针都释放(或是不再指向对象)的时候,自动释放对象

class Test {
public:
    // 无参构造函数
    Test();
    // 有参数的构造函数
    explicit Test(int a);
    // 析构函数
    ~Test();
};

Test::Test() {
    std::cout << "无参构造函数" << std::endl;
}

Test::Test(int a) {
    std::cout << "有参构造函数,a=" << a << std::endl;
}

Test::~Test() {
    std::cout << "析构函数" << std::endl;
}

// make_shared函数来创建对象,而不要手动去new,这样就可以防止我们去使用原始指针创建多个引用计数体系。

int main(int argc, const char * argv[]) {
    auto p1 = new Test; // 划分堆空间
    std::shared_ptr<Test> sp(p1); // 创建智能指针
    std::cout << sp.use_count() << std::endl; // 打印引用计数
    {
        std::shared_ptr<Test> sp2(sp); // 创建另一个智能指针
        std::cout << sp.use_count() << std::endl; // 打印引用计数
    } // sp2生命周期结束,sp引用计数减1
    std::cout << sp.use_count() << std::endl; // 打印引用计数

    auto mp = std::make_shared<int>(); // 分配堆空间,创建智能指针
    auto mp2 = mp; // 创建另一个智能指针
    
    std::cout << mp2.use_count() << std::endl;
    return 0;

}


空指针

空指针不指向任何对象,在试图使用一个指针前可以先检查指针是否为空。

得到空指针最直接的办法就是用字面值nullptr来初始化指针。

// 空指针的创建方法
int *p1 = nullptr;
int *p2 = 0;
// 需要导入 #include cstdlib
#include <cstdlib>
int *p3 = NULL; // 等价于 int *p3 = 0;
// 不能直接将int变量赋值给指针
int zero = 0;
pi = zero; //错误:不能直接赋值!

void* 指针

void*是一种特殊的指针类型,可用于存放任意对象的地址。一个void* 指针存放着一个地址,但是该地址中存放的是什么类型的对象并不透明。

指向指针的指针

一般来说,声明符中修饰符的个数没有限制,当有多个修饰符连写在一起时,按照其逻辑关系详加解释即可。

指针是内存中的对象,有自己的地址,允许把指针的地址再存放到另一个指针中。

通过*的个数可以区分指针的级别,即为 **表示指向指针的指针,***表示指向指针的指针的指针。

int ival = 1024;
int *p = &ival; // p指向一个int型的数
int **pp = &p; // pp指向一个int型的指针
// 解引用 int型指针会得到一个int型的数,解引用指向指针的指针会得到一个指针。

指向常量的指针(pointer to const)不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针。

// 指针和const
const double pi = 3.14; // pi是常量,值不能改变
double *ptr = &pi; // 错误:ptr是一个普通指针
const double *cptr = &pi; // 正确:cptr可以指向一个双精度常量
*cptr = 42; // 错误:不能给*cptr赋值

double dval = 3.14;  // dval是一个双精度浮点数,它的值可以改变
cptr = &dval; // 正确:但是不能通过cptr改变dval的值 可以通过其他途径修改dval的值

指针和数组

数组的元素也是对象,对数组使用下标运算符得到该数组指定位置的元素。对数组的元素使用取地址符能得到指向该元素的指针。

数组还有一个特性:在用到数组名字的地方,很多时候编译器会自动地把数组替换为一个指向数组首元素的指针。(数组名被解释为指向该数组的第一个元素的指针)

// 指针和数组
string nums[] = {"one", "two", "three"};
string *p = &nums[0];
string *p2 = nums;
cout << "p中存放的地址:" << p << endl;
cout << "p2中存放的地址:" << p2 << endl;
cout << "p的解引用:" << *p << endl;
cout << "p2的解引用:" << *p2 << endl;

// auto推断和decltype
int ia[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
auto ia2(ia);
cout << "ia2的类型:" << typeid(ia2).name() << endl;
// ia2 = 42;
*ia2 = 42;
auto ia3(&ia[0]);
cout << "ia2中存放的地址:" << ia2 << endl;
cout << "ia3中存放的地址:" << ia3 << endl;
cout << "ia2的解引用:" << *ia2 << endl;
cout << "ia3的解引用:" << *ia3 << endl;

decltype(ia) ia4 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// ia4 = p; // 错误:不能用整形指针给数组赋值
cout << "ia4的类型:" << typeid(ia4).name() << endl;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值