Mic*_*ael 59 c++ new-operator dynamic-memory-allocation c++11 c++14
鉴于可用性make_unique和make_shared自动删除unique_ptr以及shared_ptr析构函数,在C++ 14中使用new和使用的情况(除了支持遗留代码之外)是delete什么?
Bar*_*rry 36
虽然智能指针是优选在许多情况下原始指针,仍有大量的使用情况为new/ delete在C++ 14.
如果您需要编写任何需要就地构造的东西,例如:
您需要使用展示位置new,可能还需要delete.没办法解决这个问题.
对于您要编写的某些容器,您可能希望使用原始指针进行存储.
即使对于标准的智能指针,new如果你想使用自定义删除器,你仍然需要make_unique,make_shared但不允许这样做.
它是用一种比较常见的选择make_unique和make_shared,而不是原始的调用new.但这不是强制性的.假设您选择遵循该约定,则可以使用一些地方new.
首先,非自定义展示位置new(我将忽略"非自定义"部分,并将其称为展示位置new)是一种与标准(非展示位置)完全不同的纸牌游戏new.它在逻辑上与手动调用析构函数配对.Standard new都从免费商店获取资源,并在其中构建对象.它配对delete,破坏物体并将存储回收到免费商店.从某种意义上说,标准new调用new内部放置,而标准delete内部调用析构函数.
放置new是您在某些存储上直接调用构造函数的方式,并且是高级生命周期管理代码所必需的.如果您正在实施optional,union对齐存储上的类型安全,或智能指针(具有统一存储和非统一生命周期等make_shared),您将使用放置new.然后在特定对象的生命周期结束时,直接调用它的析构函数.像非配置new和delete,布局new和成对出现的手动析构函数调用.
自定义展示位置new是另一个使用原因new.自定义放置new可用于从非全局池分配资源 - 作用域分配,或分配到跨进程共享内存页,分配到视频卡共享内存等 - 以及其他用途.如果您想编写make_unique_from_custom使用自定义展示位置new分配其内存,则必须使用该new关键字.自定义放置new可以像放置新的一样(因为它实际上并不获取资源,而是以某种方式传递资源),或者它可以像标准一样new(因为它获取资源,可能使用传入的参数).
自定义布局delete,如果自定义布局被称为new抛出,所以你可能需要编写.在C++中,您不调用自定义放置delete,它(C++)调用您(r重载).
最后,make_shared并且make_unique是在他们不支持自定义删除器不完整的功能.
如果您正在编写make_unique_with_deleter,您仍然可以使用它make_unique来分配数据,并将.release()其分配给您的独特删除者.如果你的删除器想要将其状态填入指向的缓冲区而不是填入unique_ptr或分成单独的分配,那么你需要在new这里使用放置.
因为make_shared,客户端代码无权访问"引用计数存根"创建代码.据我所知,你不能轻易地同时拥有"对象和引用计数块的组合分配"和自定义删除器.
此外,make_shared只要对象持久存在,就会导致对象本身的资源分配(存储)weak_ptr持久存在:在某些情况下,这可能并不理想,因此您需要做一个shared_ptr<T>(new T(...))以避免这种情况.
在您想要调用非展示位置的少数情况下new,您可以调用make_unique,然后.release()指针,如果您想要与其分开管理unique_ptr.这会增加您对资源的RAII覆盖率,并且意味着如果存在异常或其他逻辑错误,则您不太可能泄漏.
我在上面提到过,我不知道如何使用带有共享指针的自定义删除器,该共享指针可以轻松使用单个分配块.这是一个如何巧妙地做到这一点的草图:
template<class T, class D>
struct custom_delete {
std::tuple<
std::aligned_storage< sizeof(T), alignof(T) >,
D,
bool
> data;
bool bCreated() const { return std::get<2>(data); }
void markAsCreated() { std::get<2>()=true; }
D&& d()&& { return std::get<1>(std::move(data)); }
void* buff() { return &std::get<0>(data); }
T* t() { return static_cast<T*>(static_cast<void*>(buff())); }
template<class...Ts>
explicit custom_delete(Ts...&&ts):data(
{},D(std::forward<Ts>(ts)...),false
){}
custom_delete(custom_delete&&)=default;
~custom_delete() {
if (bCreated())
std::move(*this).d()(t());
}
};
template<class T, class D, class...Ts, class dD=std::decay_t<D>>
std::shared_ptr<T> make_shared_with_deleter(
D&& d,
Ts&&... ts
) {
auto internal = std::make_shared<custom_delete<T, dD>>(std::forward<D>(d));
if (!internal) return {};
T* r = new(internal->data.buff()) T(std::forward<Ts>(ts...));
internal->markAsCreated();
return { internal, r };
}
Run Code Online (Sandbox Code Playgroud)
我认为应该这样做.我试图允许无状态删除者使用a来不使用空间tuple,但我可能已经搞砸了.
在库质量的解决方案中,如果T::T(Ts...)是noexcept,我可以消除bCreated开销,因为在构造custom_delete之前不可能有必要销毁T.
| 归档时间: |
|
| 查看次数: |
3809 次 |
| 最近记录: |