我正在尝试更好地学习模板,所以我为in-placeunique_ptr
编写了一个小函数。这是我的代码:
#include <iostream>
#include <array>
#include <memory>
#include <functional>
struct A {
int a = 0;
double b = 0.0;
A() { std::cout << "c1\n"; }
A(int a) : a(a) { std::cout << "c2\n"; }
~A() { std::cout << "d\n"; }
};
template<typename T, typename... Args>
auto make_unique(void *p, Args&&... args) {
return std::unique_ptr<T, std::function<void(T*)>>(
new(p) T(std::forward<Args>(args)...),
[](T* ptr) { ptr->~T(); });
};
int main() {
std::array<char,50> buf1;
std::array<char,50> buf2;
auto o1 = make_unique<A>(buf1.data());
auto o2 = make_unique<A>(buf2.data(), 3);
}
这段代码按我的预期工作,并在对象生命周期以就地方式结束时调用构造函数/析构函数。
但这是我的问题。我喜欢将它用作 ADL(依赖于参数的查找),但是当我添加using std::make_unique;
到代码顶部时,代码编译时出错。发生这种情况似乎是因为编译器无法区分 mymake_unique()
和库中指定的内容。我想它与这个冲突:
template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args );
我想知道这是否是一种解决方法?或者最简单的方法是将 my 重命名make_unique()
为另一个函数?
如果其参数可用于创建对象,则 std make unique 不会以 SFINAE/重载友好方式进行测试。即使这样做了,您的计划也会很糟糕,因为新放置和非放置新不应该依赖于 delecate 过载选择。它们是非常不同的操作。
所以有一些改进:
template<class T>
auto placement_unique(void *p) {
return [p](auto&&...args) {
return std::unique_ptr<T, void(*)(T*)>(
::new(p) T(decltype(args)(args)...),
+[](T* ptr) { ptr->~T(); }
);
};
};
用途是:
auto pa = placement_unique<A>(ptr)( 7 );
与placement new 一样,指针和对象参数是分开的。
这可以进一步改进:
struct destroy_it {
template<class T>
void operator()(T* t)const { if (t) t->~T(); }
};
template<class T>
using unique_placed_ptr = std::unique_ptr<T, destroy_it>;
template<class T>
auto placement_unique(void *p) {
return [p](auto&&...args) {
return unique_placed_ptr<T>(
::new(p) T(decltype(args)(args)...)
);
};
};
这需要比标准多 0 的内存unique_ptr
——删除器是无状态的。它甚至在不同unique_ptr
类型之间很常见。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句