C++11 представил std::begin(std::valarray&)
, а также std::end(std::valarray&)
.
C++17 представил std::data()
, который работает с std::vector
, std::array
, C-стилем. массивы и т.д. Но почему не был введен перегруженный std::data()
для std::valarray
?
std::valarray
указывается как непрерывное хранилище, доступ к которому можно получить, взяв адрес a[0]
(см. Примечания).
std::data(std::valarray& a)
можно было просто определить для возврата &(a[0])
. Почему это не сделано? Это оплошность?
Моя мотивация заключается в том, что я работаю над универсальной библиотекой сериализации. Когда он получает непрерывные массивы двоичных чисел из источника (например, CBOR), он определяет, есть ли в целевом контейнере перегруженная функция data(container)
, функция-член container.resize(n)
, а также соответствующий value_type
(соответствующий примитивный числовой тип). Существование всех трех позволяет эффективно memcpy()
переносить исходные данные непосредственно в целевой контейнер. Если бы была перегрузка std::data(std::valarray&)
, моя жизнь упростилась бы. Его отсутствие не мешает, но делает код более запутанным.
ДОПОЛНЕНИЕ. Причина, по которой я хочу обнаружить функцию data
, заключается в том, что она сообщает мне, что целевой контейнер непрерывен. Если он непрерывен, то я могу сделать эффективную копию байта (через std::memcpy
или std::copy
не имеет большого значения). Если он не является непрерывным, то мне нужно распаковать каждый невыровненный номер исходного массива по одному и добавить его в целевой контейнер, используя push_back
, emplace
и т. д. в зависимости от типа контейнера.
ДОБАВЛЕНИЕ 2. Я решил использовать подход с адаптером и признаками вместо обнаружения наличия функции data
. Это упростит поддержку нестандартных или определяемых пользователем типов контейнеров. Мой вопрос о том, почему нет std::data(std::valarray& a)
, остается в силе.
ДОБАВЛЕНИЕ 3: я должен был уточнить, что мне нужно сделать этот хакерский прием для типизированных массивов CBOR, которые могут быть только числами. Более того, числа в исходном буфере не выровнены по границам элементов. Я знаю, что для двоичных данных может потребоваться перестановка байтов по порядку байтов, и что копирование байтов в тип с плавающей запятой может вызвать странное поведение NaN, если с ним не обращаться осторожно.
Теперь я сожалею, что упомянул о своей мотивации, и должен был оставить вопрос std::data(std::valarray& a)
сам по себе. В какое крушение превратился этот вопрос, ха-ха. :-)
memcpy()
передавать исходные данные непосредственно в целевой контейнер. Есть ли причина, по которой вы не используетеstd::copy()
/std::copy_n()
для этой цели, позволяя компилятору оптимизировать их доmemcpy
когда возможно? Вам не нужен доступ кdata()
для каждого контейнера, чтобы использоватьstd::copy/_n
, только итераторы. - person Remy Lebeau   schedule 06.02.2021std::copy
, потому что исходные данные находятся в буфере необработанных байтов, и нет гарантии, что они будут выровнены по границам элементов. Типизированные массивы CBOR, полученные в сетевом буфере, — это источник данных, если вы действительно хотите знать кровавые подробности. - person Emile Cormier   schedule 06.02.2021std::valarray
на самом деле не считается частьюSTL
, так как не соответствует философииSTL
. - person Galik   schedule 06.02.2021std::copy()
с итераторами произвольного доступа, такими как векторные массивы и массивы C, оптимизируется в код, эквивалентный memcpy. Код типаcontainer.resize(n); memcpy(std::data(container), source, n * sizeof(decltype(container)::value_type));
можно переписать какcontainer.resize(n); std::copy(source, source+n, std::begin(container));
илиcontainer.resize(n); std::copy_n(source, n, std::begin(container));
- person Remy Lebeau   schedule 06.02.2021std::copy
перейти от серединыstd::vector<uint8_t>
кstd::vector<float>
, гдеstd::vector<uint8_t>
— сетевой буфер, аstd::vector<float>
— тип назначения. Сетевой буфер содержит метаданные до того, как начнутся фактические данные массива с плавающей точкой, и не гарантируется, что данные массива с плавающей запятой будут выровнены по границеfloat
. По техническим причинам, в которые я не хочу вдаваться, я не могу получать метаданные отдельно перед получением полезной нагрузки в буфер с выравниванием по плавающей запятой. - person Emile Cormier   schedule 06.02.2021std::data(std::valarray&)
, это, вероятно, самый простой ответ. - person Emile Cormier   schedule 06.02.2021STL
всегда правильно использовалось для обозначения контейнера и алгоритмов частей стандартной библиотеки. Первоначальный авторSTL
(Степанов), создательC++
(Страуструп) и все крупные авторыC++
(Мейерс, Саттер и т. д.) используют этот термин именно так. - person Galik   schedule 06.02.2021data(std::valarray&)
(и ее вариантconst
) в пространстве имен моей библиотеки. Выполнивusing std::data;
заранее, логика десериализации через ADL найдет пользовательскую функциюdata
дляstd::valarray
в дополнение к перегруженным функциямstd::data
для других контейнеров. - person Emile Cormier   schedule 06.02.2021std::copy
из серединыstd::vector<uint8_t>
вstd::vector<float>
- конечно, можно, например:std::vector<uint8_t> buffer; /* fill buffer ... */ std::vector<float> values(n); std::copy_n(reinterpret_cast<char*>(&buffer[index]), n * sizeof(float), reinterpret_cast<char*>(values.data()));
- person Remy Lebeau   schedule 06.02.2021uint8_t
доfloat
, а затем выполнениеcopy_n
с использованием указателейfloat*
. Я был озадачен, почему кто-то с такой высокой репутацией предложил такое, хе-хе. - person Emile Cormier   schedule 06.02.2021uint8_t*
вfloat*
и скопироватьfloat
, но, как говорилось ранее, это было бы незаконно. Тем не менее, использование каламбура черезchar
допустимо для целей копирования байтов. - person Remy Lebeau   schedule 06.02.2021std::memcpy
при копировании необработанных байтов из личного стиля. Я не думаю, что стилистический выбор относится к вопросу, почемуstd::valarray
не имеет функцииdata
. Я уверен, что вопрос оstd::memcpy
иstd::copy
при работе с байтами уже задавался здесь много раз, и я проконсультируюсь с ними, чтобы пересмотреть свой стиль использованияstd::memcpy
. - person Emile Cormier   schedule 06.02.2021data
, заключается в том, что она сообщает мне, что контейнер назначения является непрерывным. Если он непрерывен, то я могу сделать эффективную копию байта (черезstd::memcpy
илиstd::copy
не имеет большого значения). Если он не является непрерывным, мне нужно распаковать каждое значение массива по одному и добавить его в целевой контейнер. - person Emile Cormier   schedule 06.02.2021std::copy/_n()
- person Remy Lebeau   schedule 06.02.2021data
, не говорит всего, что вам нужно знать о возможности безопасного использованияmemcpy
. Он не будет работать должным образом со многими классами и подвержен ошибкам. Следует добавить множество других ограничений, например, тип не должен иметь определяемый пользователем деструктор и т. д. В прошлом такие типы были POD (обычные старые данные). С недавними стандартами есть гораздо больше различий. - person Phil1970   schedule 06.02.2021std::copy
. Кроме того, копирование данных из сети очень хрупкое, так как вам нужно знать, среди прочего, об индийскости, формате с плавающей запятой и целочисленном размере. Как только вы примете во внимание все это, оптимизация копирования может не иметь большого значения, если ваши данные не содержат большие массивы заданного типа, которые не требуют преобразования. Для общей библиотеки сериализации я серьезно сомневаюсь, что надлежащие условия будут часто выполняться. - person Phil1970   schedule 06.02.2021data()
в совместимом со стандартом контейнере стандартной библиотеки нельзя использовать в качестве места назначения для операцииmemcpy
. Если вы посмотрите на большую таблицу внизу en.cppreference.com/w/cpp/container вы увидите, что его поддерживают толькоvector
иarray
(а такжеstring
), и они гарантированно сохраняют данные непрерывно, начиная с C++11. Я хорошо разбираюсь в форматах с порядком байтов и с плавающей запятой; это не первое мое родео. Наконец, я не спросил о том, какой формат сериализации мне следует использовать. - person Emile Cormier   schedule 06.02.2021data()
нельзя использовать наstd::vector<std::string>>
. Тот факт, что данные непрерывны, не гарантирует, что использованиеmemcpy
безопасно. Любой тип, который содержит ресурс, подсчитывает количество экземпляров или имеет какой-либо побочный эффект в конструкторе копирования, не должен копироваться путем копирования байтов. - person Phil1970   schedule 06.02.2021data
я также проверяю, чтоvalue_type
целевого контейнера является примитивным числовым типом, соответствующим исходному. Поэтому я бы не стал пытаться десериализовать типизированный массив чисел вvector<string>
— это было бы глупо. :-) Что касается того, почему бы не использовать существующую библиотеку, я проверил существующие, и ни одна из них не ставит все галочки в моем списке желаний. Я думаю, что смогу придумать что-нибудь получше (надеюсь). Если бы каждый автор библиотеки, обращающийся сюда за помощью, прислушивался к совету не заморачиваться, то инноваций больше не было бы. - person Emile Cormier   schedule 06.02.2021std::data
не поддерживает его не из-за того, что он медленный. - person phuclv   schedule 08.02.2021