Как прокомментировал Jarod42, я могу иметь доступ к необработанному размеру массива, если используется std::shared_ptr<T[N]>
(но не std::shared_ptr<T[]>
).
Поэтому я могу добавить перегрузку serialize
, чтобы получить размер N
через параметры шаблона и в то же время знать, что shared_ptr
содержит массив.
#include <iostream>
#include <memory>
#include <string>
#include <type_traits>
struct Writer // Toy example
{
template <typename T>
void operator()(const T& v) {std::cout << v << ", ";}
};
struct ArrayWriter // Toy example
{
ArrayWriter() {std::cout << "[";}
~ArrayWriter() noexcept {std::cout << "], ";}
template <typename T>
void operator()(const T& v) {std::cout << v << ", ";}
};
// "Regular" shared_ptr
template <typename T>
void serialize(Writer& writer, const std::shared_ptr<T> ptr)
{
static_assert(!std::is_array_v<T>,
"shared_ptr<T[]> not supported: size unknowable");
if (ptr)
writer(*ptr);
else
writer("null");
}
// shared_ptr holding an array of known size
template <typename T, std::size_t N>
void serialize(Writer& writer, const std::shared_ptr<T[N]> ptr)
{
if (ptr)
{
ArrayWriter arrayWriter;
static constexpr auto size = N;
for (std::size_t i=0; i<size; ++i)
arrayWriter(ptr[i]);
}
else
writer("null");
}
int main()
{
Writer writer;
std::shared_ptr<std::string> s{new std::string{"Hello"}};
std::shared_ptr<int[3]> n{new int[3]}; // Error prone!
std::shared_ptr<float[]> x{new float[5]}; // Size lost
n[0] = 1; n[1] = 2; n[2] = 3;
serialize(writer, s); // Outputs Hello,
serialize(writer, n); // Outputs [1, 2, 3, ],
// serialize(writer, x); // static assertion failure
return 0;
}
Рабочий пример: https://onlinegdb.com/r1R5jv0wI
Спарик все еще прав в своем ответе о том, что не может узнать размер, если ему дано shared_ptr<T>
неожиданно (мне следовало бы сформулировать свой вопрос лучше).
Дэвид Шварц отметил в комментариях, что Пользователь может не правильно инициализировать элементы массива (или использовать неправильный размер Dynami c), и мой сериализатор не сможет узнать об этом. Даже если умные указатели, содержащие необработанные массивы динамических c, могут работать в моем случае, не стоит поддерживать их.
Спасибо всем за ваши комментарии и ответы!
Приложение
Согласно этому ответу , unique_ptr<T[N]>
плохо сформировано и действительно не работает для меня в G CC.
Я обнаружил P0674R1 (Расширение make_shared для массивов поддержки) , и в нем приводится несколько примеров shared_ptr<T[N]>
, поэтому представляется законным допустить, что комитет не запретил его, когда он был принят.
Немного раздражает, что unique_ptr
и shared_ptr
не ведут себя одинаково в этом отношении.