你能分配一个与 make_shared 等效的数组吗?

Posted

技术标签:

【中文标题】你能分配一个与 make_shared 等效的数组吗?【英文标题】:Can you allocate an array with something equivalent to make_shared? 【发布时间】:2012-12-10 03:05:59 【问题描述】:
buffer = new char[64];
buffer = std::make_shared<char>(char[64]); ???

您可以使用make_shared&lt;&gt;() 为数组分配内存吗?

我可以:buffer = std::make_shared&lt;char&gt;( new char[64] );

但这仍然涉及调用 new,据我了解,make_shared 更安全、更高效。

【问题讨论】:

std::vector&lt;char&gt; buffer(64); 不,你不能做“std::make_shared(new char[64]);”。 【参考方案1】:

make_shared的重点是将托管对象合并到共享指针的控制块中,

既然您正在处理 C++11,也许使用 C++11 数组会满足您的目标?

#include <memory>
#include <array>
int main()

    auto buffer = std::make_shared<std::array<char, 64>>();

请注意,您不能像从 new[] 获得的指针那样使用共享指针,因为std::shared_ptr(例如,与std::unique_ptr 不同)不提供operator[]。您必须取消引用它:(*buffer)[n] = 'a';

【讨论】:

我无法在编译时指定数组的大小? @JoshElias 你肯定可以在编译时。你的意思是运行时间吗?这将需要您自己的类将数组大小作为构造函数参数,因为make_shared&lt;T&gt; 将其运行时参数转发给T 的构造函数。或者只是制作一个共享向量。 是的对不起我的意思是运行时。啊..这是个好主意,谢谢你教育了一个菜鸟! 支持洞察力,但您应该知道make_shared只是用于过早优化;它也是为了异常安全。 std::shared_ptr&lt;T&gt;(new T) 是一个危险信号,因为如果 shared_ptr 的构造函数恰好抛出 bad_alloc 异常,它会泄漏 new T @PeteC 我们都是对的,因为问题案例比我简洁的评论所暗示的要微妙。问题在于诸如foo(sh_ptr(new T), sh_ptr(new U)); 之类的表达式——在调用sh_ptr 的构造函数之间没有序列点,因此有效的构造顺序是new Unew Tsh_ptr(&lt;ptr to T&gt;)sh_ptr(&lt;ptr to U&gt;) .如果中间两个调用中的任何一个抛出,则 new U 被泄露。 herbsutter.com/gotw/_102【参考方案2】:

您需要共享分配的内存吗?您可以改用 std::unique_ptr 和 C++14 上可用的 std::make_unique

auto buffer = std::make_unique<char[]>(64);

C++20 中将有一个std::make_shared 版本可用:

auto buffer = std::make_shared<char[]>(64);

【讨论】:

即使您确实希望共享它,make_unique 也可以使用 std::shared_ptr&lt;char[]&gt; b; b = std::make_unique&lt;char[]&gt;(25); @Thomas 是的,make_unique 可以正常工作。但是以这种方式初始化 shared_ptr 会花费你额外的内存分配。使用make_shared时可以避免这种情况。 @PaulGroke 是的,但为了完整起见,我要补充一点,保存的分配会带来轻微的风险weak_ptr, make_shared and memory deallocation【参考方案3】:

这个怎么样?

template<typename T>
inline std::shared_ptr<T> MakeArray(int size)

    return std::shared_ptr<T>( new T[size], []( T *p ) delete [] p;  );


auto  buffer = new char[64];
auto  buffer = MakeArray<char>(64);

【讨论】:

创建新的shared_ptr 和使用make_shared 是有区别的,后者的原子操作少了1个,尽可能优先使用。 此方法也不会为数组分配引用计数,因此需要两次调用内存管理器。 考虑到 C++20 指日可待,这种“polyfill”允许我们编写非常接近于您选择的编译器支持 C++20 的 make_shared(size_t),开销将大大超过更干净、健壮的面向未来的代码。如果您将模板重命名为“make_shared_array”之类的名称,那么当您明年返回代码进行升级时,其意图就很明显了 ;-) 这极大地有助于使用可变结构缓冲区,因为许多系统调用都需要。其他变量数组方法生成阻塞强制转换警告=错误。【参考方案4】:

最有效的方法是使用下面的make_shared() 重载,它在 Boost 和 C++20 中可用。

template< class T >
shared_ptr<T> make_shared( std::size_t N );

【讨论】:

以上是关于你能分配一个与 make_shared 等效的数组吗?的主要内容,如果未能解决你的问题,请参考以下文章

在等效数组之间分配元素以实现平衡和

是否可以在 Rust 运行时确定大小的堆栈分配数组?

将 make_shared 与可变参数模板绑定

为啥在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同? [复制]

Delphi中等效的BYTE数组(BYTE [])与null终止一个整数?

嵌入式学习步骤及方法(精典)