为什么 std::unique_ptr 没有像 std::shared_ptr 那样的别名构造函数?
Why doesn't std::unique_ptr have an aliasing constructor like std::shared_ptr has?
我刚刚发现了std::shared_ptr
的"别名构造函数",发现自己在问"为什么std::unique_ptr没有相应的构造函数?
也就是说,如果要分配一个Foo
以便可以将其Bar
成员传递给应完全管理Foo
生存期的函数,能够这样做不是很好吗?
#include <memory>
struct B {}
struct A {
B b;
}
void f(std::unique_ptr<B> b);
std::unique_ptr<A> a = std::make_unique<A>();
std::unique_ptr<B> b { std::move(a), &(a->b) }; // a now invalid.
f(std::move(b)); // f now responsible for deleting the A.
这适用于 std::shared_ptr ( http://ideone.com/pDK1bc (
#include <iostream>
#include <memory>
#include <string>
struct B {
std::string s;
};
struct A {
B b;
A(std::string s) : b{s} {};
~A() { std::cout << "A deleted." << std::endl; }
};
void f(std::shared_ptr<B> b) {
std::cout << "in f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
}
int main() {
std::shared_ptr<A> a = std::make_shared<A>("hello");
std::shared_ptr<B> b { a, &(a->b) };
a.reset(); // a now invalid.
std::cout << "before f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl;
f(std::move(b)); // f now responsible for deleting the A.
std::cout << "after f" << std::endl;
return 0;
}
输出预期的
before f, b->s = hello (use_count=1)
in f, b->s = hello (use_count=1)
A deleted.
after f
没有一个合乎逻辑的理由为什么不包括这样的事情?和/或,使用带有删除A
的自定义删除器的unique_ptr<B>
模拟它是一个坏主意吗?
"问题"在于,与std::shared_ptr
不同,std::unique_ptr
的删除器没有被类型擦除。std::unique_ptr<T>
的默认删除器(大小为零,作为几乎不可见的默认类型参数编码到类型本身中(只是[](T * p){ delete p; }
。但很明显,通过 std::make_unique<B>
创建的std::unique_ptr<B>
和通过指向A
对象的B
成员创建的不能具有相同的删除器。后一种情况的删除程序必须执行一些指针算术才能获取原始指针返回A *
。这两个删除器只能具有相同的类型,如果它们都存储偏移量或指向原始对象的内部指针。这将不再具有零大小。 与手动执行new
和delete
相比,std::unique_ptr
的设计开销为零,这是一件好事。我没有看到使用自己的删除器来存储该附加指针的任何直接缺点,尽管我仍然必须遇到一个用例,我会发现这很有用。
shared_ptr
具有引用计数开销。 在其引用计数块中,它还存储了一个显式删除器(因为如果您存储在堆上,那么更多的字节是多少?
这也是为什么对基类型的shared_ptr
可以记住在没有虚拟 dtor 的情况下删除派生类型的原因。
另一方面,unique_ptr
将其删除器存储在实例中,并且默认删除器是无状态的 - 使用0字节。 这使得unique_ptr
内存使用量方面原始指针的开销为零。
无状态删除程序无法记住删除其他内容。
您可以向支持别名的unique_ptr
添加有状态删除程序,但随后必须手动添加别名。 其中一个构造函数同时采用指针和删除器。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- 引用 std::shared:ptr 以避免引用计数
- C++14 unique_ptr并使用已删除的函数'std::unique-ptr' unique_ptr错误
- 使用std :: String ptr的错误打印std :: String
- C++中的大小释放:全局运算符delete的正确行为是什么(void*ptr,std::size_t size)
- std::哈希表示无序映射中的唯一 PTR
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- 正确使用std智能指针以确保ptr安全
- 如何创建 std::string 包装器,它将 ptr 保留为 std::string 和 ptr 到创建该包装器实例的
- 为什么 std::string{ "const char ptr" } 有效?
- 为什么 gcc 4.9.0 中没有定义"void operator delete(void* ptr, std::size_t size) noexcept;"?
- 在 std::map 的值中使用非 ptr 是一种很好的做法吗
- 共享 PTR - C++:std::shared_ptr<T> 和 std::shared_ptr<T const> 有什么区别?