a review at smart pointer(3)
终于到了shared ptr
首先看一下std::make_shared
- 可能有人不知道std::pair是什么,接下来的例子是和std::pair有关系的, first和second是第一个成员和第二个成员,然后我们可以发现,第一个first和第二个second竟然可以不一样
// make_pair example
#include <utility> // std::pair
#include <iostream> // std::cout
int main () {
std::pair <int,int> foo;
std::pair <int,int> bar;
foo = std::make_pair (10,20);
bar = std::make_pair (10.5,'A'); // ok: implicit conversion from pair<double,char>
std::cout << "foo: " << foo.first << ", " << foo.second << '\n';
std::cout << "bar: " << bar.first << ", " << bar.second << '\n';
return 0;
}
// pair::operator= example
#include <utility> // std::pair, std::make_pair
#include <string> // std::string
#include <iostream> // std::cout
int main () {
std::pair <std::string,int> planet, homeplanet;
planet = std::make_pair("Earth",6371);
homeplanet = planet;
std::cout << "Home planet: " << homeplanet.first << '\n';
std::cout << "Planet size: " << homeplanet.second << '\n';
return 0;
}
- 我们发现里面有 std::shared_ptr
foo = std::make_shared (10); same as: std::shared_ptr foo2 (new int(10)); 这个东西,也就是说我们要注意两种形式的构造
// make_shared example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo = std::make_shared<int> (10);
// same as:
std::shared_ptr<int> foo2 (new int(10));
auto bar = std::make_shared<int> (20);
auto baz = std::make_shared<std::pair<int,int>> (30,40);
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';
return 0;
}
接下来是 allocate_shared
- 文档里有说 This function uses alloc to allocate storage for the object. A similar function, make_shared uses ::new to allocate the storage instead. 这个是用alloc分配的
// allocate_shared example
#include <iostream>
#include <memory>
int main () {
std::allocator<int> alloc; // the default allocator for int
std::default_delete<int> del; // the default deleter for int
std::shared_ptr<int> foo = std::allocate_shared<int> (alloc,10);
auto bar = std::allocate_shared<int> (alloc,20);
auto baz = std::allocate_shared<std::pair<int,int>> (alloc,30,40);
std::cout << "*foo: " << *foo << '\n';
std::cout << "*bar: " << *bar << '\n';
std::cout << "*baz: " << baz->first << ' ' << baz->second << '\n';
return 0;
}
接下来是std::static_pointer_cast
// static_pointer_cast example
#include <iostream>
#include <memory>
struct A {
static const char* static_type;
const char* dynamic_type;
A() { dynamic_type = static_type; }
};
struct B: A {
static const char* static_type;
B() { dynamic_type = static_type; }
};
const char* A::static_type = "class A";
const char* B::static_type = "class B";
int main () {
std::shared_ptr<A> foo;
std::shared_ptr<B> bar;
foo = std::make_shared<A>();
// cast of potentially incomplete object, but ok as a static cast:
bar = std::static_pointer_cast<B>(foo);
std::cout << "foo's static type: " << foo->static_type << '\n';
std::cout << "foo's dynamic type: " << foo->dynamic_type << '\n';
std::cout << "bar's static type: " << bar->static_type << '\n';
std::cout << "bar's dynamic type: " << bar->dynamic_type << '\n';
return 0;
}
- 输出:
foo's static type: class A
foo's dynamic type: class A
bar's static type: class B
bar's dynamic type: class A
- 首先,const char* a::static_type = 'class a', 静态区成员a::static_type是 'class a',
- 然后,const char* b::static_type = 'class b',静态区成员b::static_type是 'class b',
- 然后执行 std::shared_ptr< A > foo; std::shared_ptr< B > bar,bar和foo这两个现在是null了
- 然后执行 foo = std::make_shared< A >() ,构造函数使得foo的:const char* dynamic_type 等于 'class a',
- 执行 bar=std::static_pointer< B >(foo), static_cast使得:bar为foo的值,所以bar是foo了
- 所以foo的值是:一个a::static_type是class a,一个dynamic type是class a
- bar是foo,bar的dynamic type是foo的dynamic type是a
- bar的static type没有变,因为bar的static type并不是foo的static type,即使bar变成了foo,也只是非静态区变了,静态区没变
-
真是太难了。。。
dynamic_pointer_cast 待更
智能指针的const cast
- 虽然cpp官网上对于普通指针的const cast讲解例子只写了如何去除一个const,但是它有明确的说一点"either to be set or to be removed",所以我们可以猜出,去除 / 添加一个const在智能指针里也是合法的
// static_pointer_cast example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo;
std::shared_ptr<const int> bar;
foo = std::make_shared<int>(10);
bar = std::const_pointer_cast<const int>(foo);
std::cout << "*bar: " << *bar << '\n';
*foo = 20;
std::cout << "*bar: " << *bar << '\n';
return 0;
}
- 这个例子里,是说如何把一个int* 变成 const int * , c++ 的const cast大部分情况下是可以按照你预期的结果正常工作的,但是也有些许例外,这取决于如何声明、编译器如何优化。上面的例子里,输出结果是10和20
get_deleter
// get_deleter example
#include <iostream>
#include <memory>
struct D { // a verbose array deleter:
void operator()(int* p) {
std::cout << "[deleter called]\n";
delete[] p;
}
};
int main () {
std::shared_ptr<int> foo (new int[10],D());
int * bar = new int[20];
// use foo's deleter to delete bar (which is unmanaged):
(*std::get_deleter<D>(foo))(bar);
return 0;
// foo's deleter called automatically
}
- 首先这个例子初始化了一个有10单位长度智能指针,由于它声明的是int,然后第一个参数是一个int[],所以普通的std deleter是不管用的,因为只删除首地址,所以要自定义删除器D
struct D {
void operator()(int* p) {
std::cout << "";
delete[] p;
}
}
- 注意是谁delete[] p,这是手动构造删除器的目的
- 但是下面还有一个int * bar = new int [20]这个东西
- 然后我们用std::get_deleter< D > (foo) 可以删除foo,这个类型是一个删除器指针
- 于是,我们可以连续指针操作:
(*std::get_deleter<D>(foo)) // 还是一个删除器
- 于是继续
(*std::get_deleter<D>(foo))(bar); // 删除bar
- 网上有很多深刻的讨论关于为什么智能指针有两种获取deleter的方式,我觉得我是看不懂了,大概是unique的要设计成模版,为了保持低内存而不把deleter当作类内的一部分,shared并不太过care内存,所以两种获取方式也就可以理解了。
swap
- swap是重载的函数
// shared_ptr swap specialization
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo (new int(10));
std::shared_ptr<int> bar (new int(20));
swap(foo,bar);
std::cout << "foo: " << *foo << '\n';
std::cout << "bar: " << *bar << '\n';
return 0;
}
operator <<
// shared_ptr i/o
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> foo (new int (10));
std::cout << " foo: " << foo << '\n';
std::cout << "*foo: " << *foo << '\n';
return 0;
}
输出结果是
foo: 0x920d90
*foo: 10
- 注:我还没有试过unique ptr是否有 << 的 operator overloading ,反正文档上没有
relational operator
- 不写了
浙公网安备 33010602011771号