This answer引用N4082,其中显示即将对std::shared_ptr
进行的更改将允许T[]
和T[N]
变体:
与数组的
unique_ptr
部分特化不同,shared_ptr<T[]>
和shared_ptr<T[N]>
都有效,两者都会导致在托管的对象数组上调用delete[]
。< / p>template<class Y> explicit shared_ptr(Y* p);
需要:
Y
应为完整类型。当delete[] p
是数组类型时,表达式T
或delete p
当T
不是数组类型时,应该是格式良好的,应该有明确定义的行为,并且不得抛出异常。当T
为U[N]
时,Y(*)[N]
应可转换为T*
;当T
为U[]
时,Y(*)[]
可转换为T*
;否则,Y*
应可转换为T*
。
除非我弄错了,否则Y(*)[N]
只能通过获取数组的地址来形成,而shared_ptr
显然不能拥有或删除数组的地址。我也没有看到N
以任何方式使用强制托管对象大小的任何迹象。
允许T[N]
语法的动机是什么?它是否产生任何实际效益,如果是,它是如何使用的?
答案 0 :(得分:6)
您可以获取指向嵌套对象的指针,该嵌套对象与std::shared_ptr
共享所有权到包含对象。如果此嵌套对象恰好是一个数组,并且您希望将其作为数组类型进行访问,则实际上需要使用T[N]
和T
以及N
:
#include <functional>
#include <iostream>
#include <iterator>
#include <memory>
#include <queue>
#include <utility>
#include <vector>
using queue = std::queue<std::function<void()>>;
template <typename T>
struct is_range {
template <typename R> static std::false_type test(R*, ...);
template <typename R> static std::true_type test(R* r, decltype(std::begin(*r))*);
static constexpr bool value = decltype(test(std::declval<T*>(), nullptr))();
};
template <typename T>
std::enable_if_t<!is_range<T>::value> process(T const& value) {
std::cout << "value=" << value << "\n";
}
template <typename T>
std::enable_if_t<is_range<T>::value> process(T const &range) {
std::cout << "range=[";
auto it(std::begin(range)), e(std::end(range));
if (it != e) {
std::cout << *it;
while (++it != e) {
std::cout << ", " << *it;
}
}
std::cout << "]\n";
}
template <typename P, typename T>
std::function<void()> make_fun(P const& p, T& value) {
return [ptr = std::shared_ptr<T>(p, &value)]{ process(*ptr); };
// here ----^
}
template <typename T, typename... M>
void enqueue(queue& q, std::shared_ptr<T> const& ptr, M... members) {
(void)std::initializer_list<bool>{
(q.push(make_fun(ptr, (*ptr).*members)), true)...
};
}
struct foo {
template <typename... T>
foo(int v, T... a): value(v), array{ a... } {}
int value;
int array[3];
std::vector<int> vector;
};
int main() {
queue q;
auto ptr = std::make_shared<foo>(1, 2, 3, 4);
enqueue(q, ptr, &foo::value, &foo::array, &foo::vector);
while (!q.empty()) {
q.front()();
q.pop();
}
}
在上面的代码中q
只是一个简单的std::queue<std::function<void()>>
但我希望你能想象它可以是一个线程池,将处理加载到另一个线程。实际安排的处理也是微不足道的,但是,我希望你能想象它实际上是一些大量的工作。
答案 1 :(得分:2)
除非我弄错了,否则
Y(*)[N]
只能通过获取地址来形成 一个数组,显然不能被shared_ptr
拥有或删除。
不要忘记shared_ptr
是一个通用资源管理实用程序,可以使用自定义解除分配器构建:
template<class Y, class D> shared_ptr(Y* p, D d);
这样的用户提供的解除分配器可以执行delete
/ delete[]
以外的操作。例如,如果所讨论的数组是文件描述符数组,那么&#34; deallocator&#34;可以关闭所有这些。
在这种情况下,shared_ptr
在广泛使用的意义上不拥有该对象,因此可以通过获取其地址绑定到现有数组。