短版
别名构造函数可以指向任何类型的对象,因此您可以创建任何类型的别名 shared_ptr(理论上)。简而言之,引用计数与别名类型解耦。
长版
别名构造函数创建一个新的 shared_ptr,但重新使用控制块(它保存分配信息、引用计数等)。 &pii->first 的结果是int*,所以应该是shared_ptr<int>,因为取消引用指针会返回int&。
这也意味着别名构造函数没有关于释放或分配存储在别名指针中的类型的信息,这正是别名构造函数可能很危险的原因:你告诉用户它参与了引用计数,但是,有没有明确保证它会这样做。这可能会导致取消引用释放的内存或内存泄漏,并错误地延长原始 shared_ptr 的生命周期。在这种情况下,正确使用了别名构造函数(将构造对内的指针的生命周期与对本身的生命周期联系起来),但是,无论何时使用别名构造函数都应谨慎。您通常应该使用别名构造函数来创建指向集合(如对、元组、数组或结构)内的值的指针,以确保指针在新指针的持续时间内保持有效。
使用不相关的值可能会出现严重错误的示例如下:
#include <memory>
#include <utility>
using int_pair = std::pair<int, int>;
// Since this aliases a local variable, which goes out-of-scope
// immediately, dereferencing the variable will reference junk memory.
// It will also increment the shared_count of `p`, which may lead
// to a longer lifetime than desired.
// (This is obviously wrong, and that's the point).
std::shared_ptr<int> temporary_reference(std::shared_ptr<int_pair>& p)
{
int x = 5;
return std::shared_ptr<int>(p, &x);
}
// Since this aliases a newly allocated variable, this will create a memory
// leak, since `new int(5)` will never be properly deleted.
// It will also increment the shared_count of `p`, which may lead
// to a longer lifetime than desired.
// (This is obviously wrong, and that's the point).
std::shared_ptr<int> memory_leak(std::shared_ptr<int_pair>& p)
{
return std::shared_ptr<int>(p, new int(5));
}
// This references an internal value in `p` and ties the lifetime
// of `p` to the aliased pointer, to ensure that deleting p
// does not invalidate the aliased pointer.
std::shared_ptr<int> aliased_value(std::shared_ptr<int_pair>& p)
{
return std::shared_ptr<int>(p, &p->first);
}
int main()
{
std::shared_ptr<int_pair> p(new int_pair(5, 3));
auto i1 = temporary_reference(p);
auto i2 = memory_leak(p);
auto i3 = aliased_value(p);
return 0;
}
如果我们使用指向&p->first 的原始指针,而不是别名shared_ptr,并从外部删除对p 的引用,则指针可能会变得无效。使用别名构造函数可确保内部指针在别名 shared_ptr 的生命周期内有效。
使用原始指针可能会出错的示例如下:
#include <memory>
#include <utility>
using int_pair = std::pair<int, int>;
int main()
{
std::shared_ptr<int_pair> p(new int_pair(5, 3));
int& i = p->first;
p.reset();
// the reference to i is no longer valid,
// since the shared count of the control block of `p` is now 0.
// if we had used an aliased shared_ptr, it still would be valid
return 0;
}