a review at smart pointer(前言)

ref: MSDN

指针的定义:指针是存储对象内存地址的变量。
C 和 C++ 指针的用法有:

  1. 分配堆内存的新对象
  2. 向一个函数传递另外一个函数
  3. 迭代数组或其他数据结构中的元素

在 C 风格的编程中,裸指针适用于上述三种描述。但是,裸指针是导致很多问题的元凶,因此除非在有显著性能优势且清楚在删除对象时哪个指针有最终的所有权时,不要用裸指针。

现代 C++ 提供智能指针来负责分配对象、迭代器和遍历数据结构们,以及传递函数时使用的 lambda 表达式

裸指针

指针是变量,它存储对象在内存中的地址,它也用于访问对象。裸指针的定义是:生命周期不受封装对象控制的指针,这不同于智能指针。裸指针可以被赋值为另一个非指针变量的地址,或者可以被赋值为 nullptr,未被赋值的裸指针随机被赋值一个地址。

指针可以被取消引用(dereference),返回它指向的对象值。

int* p = nullptr; // declare pointer and initialize it
                      // so that it doesn't store a random address
int i = 5;
p = &i; // assign pointer to address of object
int j = *p; // dereference p to retrieve the value at its address

一个指针可以指向一个有类型的对象或者 void . 当一个程序在 heap 分配对象时,它接收这个对象的地址(以指针的形式),如此的指针叫做 owing pointer ,一个 owing pointer (or a copy of it),在不再需要那个 heap object 的时候,必须显式的 free 掉这个指针。否则就会内存泄漏,即此内存的地址没法给任何其他的程序去用了。用 new 分配出来的内存必须搭配 delete 或者 delete[]。

    MyClass* mc = new MyClass(); // allocate object on the heap
    mc->print(); // access class member
    delete mc; // delete object (please don't forget!)

一个指针,假设没有被声明为 const 指针,那么就可以自增或者自减到内存中的其他位置,这种操作叫做指针的算术运算。在 C 语言中,数组的迭代(或其他数据结构)会用到这种运算。const 指针不能变更到内存的其他位置。
在六十四位的操作系统中,指针就有六十四个 bit,一个指针的尺寸决定于它的可寻址空间有多少。所有指针的拷贝都指向同一个内存地址,指针(同引用)在 C++ 程序中经常被用于传递对象的地址(而不是传递整个大对象),当定义一个函数的时候,规定指针参数为 const ,除非你想改这个对象,但是实际上,常引用比常量指针更常用于传递参数,除非此对象的值是 nullptr。
Pointers to functions允许函数被传递到其他函数中,在 C 语言中称作 call backs,现代 C++ 转而使用 lambda 表达式。

指针和数组有很大的关联,当一个数组在函数传参的时候,它传递的是第一个元素的地址

#include <iostream>

void func(int arr[], int length)
{
    // returns pointer size. not useful here.
    size_t test = sizeof(arr);

    for(int i = 0; i < length; ++i)
    {
        std::cout << arr[i] << " ";
    }
}

int main()
{

    int i[5]{ 1,2,3,4,5 };
    // sizeof(i) = total bytes
    int j = sizeof(i) / sizeof(i[0]);
    func(i,j);
}

sizeof 操作符返回数组有几个 bytes,除以一个元素的 sizeof 就是数组的长度,当一个数组被当成参数的时候,会变成一个指针,sizeof一个指针对于 x86 机器来说返回四个 byte,对于 x64 机器来说返回 8个 byte。
指针的算数运算可以用在非 const 指针让它们指向其它内存地址,指针可以用++, +=, -=, --来自增或者自减,这种方法在没类型的数据面前特别有用,比如 void*指针会自增一个 byte,一个有类型的指针按照它指向的值的 sizeof 自增。

void* 指针

(这段翻译了也没有原文效果好,不翻译了)
A pointer to void simply points to a raw memory location. Sometimes it's necessary to use void* pointers, for example when passing between C++ code and C functions.

When a typed pointer is cast to a void pointer, the contents of the memory location are unchanged. However, the type information is lost, so that you can't do increment or decrement operations. A memory location can be cast, for example, from MyClass* to void* and back again to MyClass*. Such operations are inherently error-prone and require great care to avoid errors. Modern C++ discourages the use of void pointers in almost all circumstances.

Pointers to Functions

(这段无关紧要,不翻译了)
In C-style programming, function pointers are used primarily to pass functions to other functions. This technique allows the caller to customize the behavior of a function without modifying it. In modern C++, lambda expressions provide the same capability with greater type safety and other advantages.

A function pointer declaration specifies the signature that the pointed-to function must have:

// Declare pointer to any function that...

// ...accepts a string and returns a string
string (*g)(string a);

// has no return value and no parameters
void (*x)();

// ...returns an int and takes three parameters
// of the specified types
int (*i)(int i, string s, double d);

const 和 volatile
const和volatile关键字改变了系统对待指针的方式,const指针规定在初始化之后其值不能被修改,也就是说指针被保护以至于不能被修改。volatile关键字规定了值可以被其他程序改变的变量(多线程?)因此,volatile关键字用于声明shared memory中可以被多线程修改的或者全局的数据(用于沟通的、用于interrupt service routines的)
当一个变量被声明为volatile时,每一次程序要访问这个变量时,编译器都从内存重新读取它的值,这样显著的减少了编译器优化,however,当变量的状态可以不寻常的改变时,这是唯一允许这个程序可以正常运行的方式。

这个blog写的很好 https://www.cnblogs.com/chio/archive/2007/11/24/970632.html

To declare the object pointed to by the pointer as const or volatile, use a declaration of the form:
要将指针指向的对象声明为const或volatile,请使用以下形式的声明:

const char *cpch;
volatile char *vpch;

To declare the value of the pointer — that is, the actual address stored in the pointer — as const or volatile, use a declaration of the form:
声明指针的值-也就是说,实际的地址存在了指针里而不是指针指向的对象里时,用这个声明。

char * const pchc;
char * volatile pchv;

分割线,前方高能请撤离。

下一段我觉得谁也搞不懂,不翻译了,感兴趣自己去MSDN开发文档去

The C++ language prevents assignments that would allow modification of an object or pointer declared as const. Such assignments would remove the information that the object or pointer was declared with, thereby violating the intent of the original declaration. Consider the following declarations:

const char cch = 'A';
char ch = 'B';

Given the preceding declarations of two objects (cch, of type const char, and ch, of type char), the following declaration/initializations are valid:

const char *pch1 = &cch;
const char *const pch4 = &cch;
const char *pch5 = &ch;
char *pch6 = &ch;
char *const pch7 = &ch;
const char *const pch8 = &ch;
此处省略一万字 参见https://docs.microsoft.com/en-us/cpp/cpp/const-and-volatile-pointers?view=msvc-160的后两段。

new和delete

C++滋瓷动态对象的分配和销毁,通过使用new和delete操作符,这些操作符在空闲区(free store)里分配和析构对象。new操作符调用operator new,delete操作符调用operator delete。
C++标准库里的new函数支持内存分配失败的时候抛出一个std::bad_alloc,假设你要是不想要那个throw,你就要用黑魔法了。。。这辈子也用不到呵呵呵。。。

The new function in the C++ Standard Library supports the behavior specified in the C++ standard, which is to throw a std::bad_alloc exception if the memory allocation fails. If you still want the non-throwing version of new, link your program with nothrownew.obj. However, when you link with nothrownew.obj, the default operator new in the C++ Standard Library no longer functions.

For a list of the library files in the C Runtime Library and the C++ Standard Library, see CRT Library Features.

new操作符

编译器将调用operator new翻译成这样

char *pch = new char[BUFFER_SIZE];

重复调用operator new将返回不同的指针,假设内存不足,会抛出一个std::bad_alloc,假设你用了黑魔法,那么就返回一个nullptr
你也可以写一个routine来释放内存重新alloc,更多信息参见 Handling insufficient memory
You can write a routine that attempts to free memory and retry the allocation. For more information, see _set_new_handler. For details on the recovery scheme, see the section.

operator new的第一个参数是size_t,在<stddef.h>中定义,返回类型是void* 。不想写了,这段和smart pointer没什么关系,待更。。而且MSDN给的例子真是过于玄学。

posted @ 2021-01-02 16:40  五个桔核  阅读(122)  评论(0)    收藏  举报