张掖网站建设推广,cpa项目怎么做必须有网站么,网站论坛怎样建设,企业网站开发有哪些参考资料#xff1a;
《C Primer》第5版《C Primer 习题集》第5版
12.1.5 unique_ptr#xff08;P417#xff09;
unique “拥有”它所指向的对象#xff0c;某个时刻只能有一个 unique_ptr 指向一个给定对象。 当我们定义一个 unique_ptr 时#xff0c;需要将其绑定到…参考资料
《C Primer》第5版《C Primer 习题集》第5版
12.1.5 unique_ptrP417
unique “拥有”它所指向的对象某个时刻只能有一个 unique_ptr 指向一个给定对象。 当我们定义一个 unique_ptr 时需要将其绑定到一个 new 返回的指针上且必须采用直接初始化的形式
unique_ptrdouble p1; // 空unique_ptr
unique_ptrint p2(new int()); // 指向一个值初始化的intunique_ptr 不支持普通的拷贝和赋值操作
unique_ptrstring p1(new string(hello));
unique_ptrstring p2(p1); // 错误
unique_ptrstring p3;
p3 p2; // 错误我们可以通过 release 或 reset 将指针的所有权从一个非 const unique_ptr 转移给另一个 unique_ptr
unique_ptrstring p1(new string(hello));
unique_ptrstring p2(p1.release());
unique_ptrstring p3;
p3.reset(p2.release());传递unique_ptr参数和返回unique_ptr
不能拷贝 unique_ptr 的规则有一个例外我们可以拷贝或赋值一个将要被摧毁的 unique_ptr
unique_ptrint clone(int p) {unique_ptrint ret(new int(p));return ret;
} // 正确向unique_ptr传递删除器
unique 默认使用 delete 释放指向的对象。与 shared_ptr 不同的是我们需要在构造 unique_ptr 时提供删除器的类型
unique_ptrobjT, delT p(new objT, fcn);以上一篇笔记中提到的网络连接类为例
void f(destination d /* 其他参数 */) {connection c connect(d);unique_ptrconnection, decltype(end_connection)*p(c, end_connection);// 当p被销毁时调用end_connection
}12.1.6 weak_ptrP420
weak_ptr 是一种不控制所指向对象生存期的智能指针指向由一个 shared_ptr 管理的对象。将 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数一旦最后一个指向对象的 shared_ptr 被销毁即使有 weak_ptr 指向对象对象也还是会被释放。 当我们创建一个 weak_ptr 时要用 shared_ptr 来初始化它
auto p make_sharedint();
weak_ptrint wp(p);上述代码中 wp 不会改变 p 的引用计数。由于 wp 指向的对象可能被释放掉我们不能使用 weak_ptr 直接访问对象而必须调用 lock
if(shared_ptrint np wp.lock()){ // 如果np不为空则条件成立...
}核查指针类
为了展示 weak_ptr 的用途我们为 StrBlob 类定义一个伴随指针类 StrBlobPtr 类中保存一个 weak_ptr 指向 StrBlob 的 data 成员。使用 weak_ptr 可以阻止用户访问一个不再存在的 vector 。
class StrBlobPtr {
public:StrBlobPtr(): curr(0) {}StrBlobPtr(StrBlob a, size_t sz 0) :wptr(a.data), curr(sz){}string deref() const;StrBlobPtr incr();
private:shared_ptrvectorstring check(size_t, const string ) const;weak_ptrvectorstring wptr;size_t curr; // 在数组中的当前位置
};StrBlobPtr 的 check 成员和 StrBlob 中的同名成员不同它还要额外检查指向的 vector 是否存在
shared_ptrvectorstring
StrBlobPtr::check(size_t i, const string msg)const {auto ret wptr.lock();if (!ret)throw runtime_error(unbound StrBlobPtr);if (i ret-size())throw out_of_range(msg);return ret;
}指针操作
我们定义 deref 和 incr 用来解引用和递增 StrBlobPtr
string StrBlobPtr::deref()const {auto p check(curr, dereference past end);return (*p)[curr];
}StrBlobPtr StrBlobPtr::incr() {check(curr, increment past end of StrBlobPtr);curr;return *this;
}由于我们在初始化 StrBlobPtr 时需要用到 StrBlob 中的 data 成员所以我们要将 StrBlobPtr 声明成 StrBlob 的友元。
12.2 动态数组P423
C 和标准库提供了两种一次分配一个对象数组的方法。在大多数情况下我们应该使用容器而非动态数组使用容器的类可以使用默认版本的拷贝、赋值、析构操作而使用动态数组的类必须定义自己版本的操作。
new和数组P423
为了让 new 分配一个对象数组我们要在类型名后跟一对方括号在其中指明要分配的对象的数目
int *pia new int[get_size()]; // 方括号中必须为整型但不必为常量也可以用类型别名来分配数组
using arrT int[1024];
int *p new arrT;分配一个数组会得到一个元素类型的指针
无论用 new T[] 还是类型别名我们得到的都是一个指向数组元素类型的指针而不是一个数组。下面的代码验证了这个事实
int x 0;
decltype(new int[10]) p1 x; // 正确
int arr[10];
decltype(arr) p2 x; // 错误动态数组并不是数组类型 初始化动态分配对象的数组
默认情况下new 分配的对象不论是单个对象还是数组都是默认初始化的。要对数组中的元素执行值初始化可以在大小后跟一对圆括号
int *pia1 new int[10]; // 10个默认初始化的int
int *pia2 new int[10](); // 10个值初始化的int在新标准中我们还可以提供初始值列表
int *pia3 new int[10] {0, 1, 2, 3};动态分配一个空数组是合法的
char arr[0]; // 错误
char *cp new char[0]; // 正确当我们用 new 分配一个大小为 0 的数组时new 返回一个合法的非空指针。
释放动态数组
为了释放动态数组我们也要在 delete 后跟一对方括号
delete p; // p必须指向一个动态分配的对象或为空
delete [] pa; // pa必须指向一个动态分配的对象数组或为空数组中的元素按逆序销毁。如果我们在 delete 一个数组时忽略了方括号或在 delete 一个对象时使用了方括号结果是未定义的。
前面提到当我们使用类型别名来定义数组类型时在 new 中可以不使用方括号但是在 delete 时则必须使用方括号
using arrT int[1024];
auto p new arrT;
delete[] p;此处产生一个疑问既然前面提到new[] 得到的仅仅是一个指针而并不是一个数组那么 delete[] 是怎么知道需要释放多少空间的呢答案见C中delete是如何获知需要释放的内存(数组)大小的 - 知乎 (zhihu.com) 智能指针和动态数组
标准库提供了一个可以管理 new 分配的数组的 unique_ptr 版本
unique_ptrint[] up(new in[10]);
up.release(); // 自动使用delete[] 当 unique_str 指向一个数组时我们不能使用点运算符和箭头运算符但我们可以使用下标运算符访问数组中的元素。
shared_ptr 不支持直接管理动态数组。如果希望使用 shared_ptr 管理动态数组必须定义自己的删除器
shared_ptrint sp(new int[10], [](int *p) {delete[] p; });如果未提供删除器shared_ptr 将使用 delete 释放一个动态数组这个行为是未定义的。由于 shared_ptr 不支持下标运算符为了访问访问数组中的元素必须用 get 获得一个内置指针
for (size_t i 0; i ! 10; i) {*(sp.get() i) i;
}12.2.2 allocator类P427
new 在灵活性上有一些局限因为它将内存分配和对象构造组合在一起了。当分配一大块内存时我们通常希望将内存分配和对象构造分离而将内存分配和对象构造组合在一起可能造成不必要的浪费
// 初始化了n个string但某些string可能永远用不到
string *const p new string[n];此外没有默认构造函数的类不能用 new 分配动态数组。
allocator类
allocator 类定义在头文件 memory 中它帮助我们将内存分配和对象构造分离开来。 allocatorstring alloc;
const auto p alloc.allocate(n); // 分配n个未初始化的stringallocator分配未构造的内存
auto q p; // 顶层const被忽略
alloc.construct(q);
alloc.construct(q, 10, c);
alloc.construct(q, hi);当我们用完对象后必须对每个元素调用 destroy 销毁它们
while(q ! p){alloc.destroy(--q); // 释放真正构造的string
}调用 deallocate 释放内存
alloc.deallocate(p, n);拷贝和填充未初始化内存的算法
标准库还为 allocator 类定义了两个伴随算法定义在头文件 memory 中 allocatorstring alloc;
vectorstring vs {hello, hi, him};
auto p alloc.allocate(vs.size() * 2);
auto q uninitialized_copy(vs.begin(), vs.end(), p);
uninitialized_fill_n(q, vs.size(), world);allocatorstring alloc;
vectorstring vs {hello, hi, him};
auto p alloc.allocate(vs.size() * 2);
auto q uninitialized_copy(vs.begin(), vs.end(), p);
uninitialized_fill_n(q, vs.size(), world);