1. Это пример бритвы Оккама, принятой драконами, которые на самом деле пишут компиляторы: не давайте больше гарантий, чем необходимо для решения проблемы, потому что иначе ваша рабочая нагрузка удвоится без компенсации. Сложные классы, адаптированные к модному оборудованию или к историческому оборудованию, были частью проблемы. (намекает Бауммит Оген и М.М.)
2. (смежные = имеющие общую границу, рядом или вместе в последовательности)
Во-первых, это не значит, что объекты типа T всегда или никогда не занимают непрерывную память. В одном двоичном файле могут быть разные макеты памяти для одного и того же типа.
[class.derived] §10 (8): Подобъект базового класса может иметь макет, отличный от...
Этого было бы достаточно, чтобы откинуться назад и убедиться, что происходящее на наших компьютерах не противоречит стандарту. Но давайте изменим вопрос. Правильнее было бы спросить:
Разрешает ли стандарт массивы объектов, которые не занимают непрерывное хранилище по отдельности, и в то же время каждые два последовательных подобъекта имеют общую границу?
Если это так, то это сильно повлияет на то, как char* арифметика соотносится с T* арифметикой.
В зависимости от того, понимаете ли вы стандартную цитату OP, означающую, что только подобъекты имеют общую границу, или что внутри каждого подобъекта байты имеют общую границу, вы можете прийти к разным выводам.
Предполагая первое, вы обнаружите, что «непрерывно распределенные» или «хранящиеся непрерывно» могут просто означать &a[n]==&a[0] + n (§23.3.2.1), что является утверждением об адресах подобъектов, которое не подразумевало бы, что массив находится в одной последовательности смежных байтов.
Если вы предполагаете более сильную версию, вы можете прийти к выводу 'element offset==sizeof(T)', выдвинутому в T* против арифметики указателей char* Это также подразумевало бы, что можно заставить в противном случае, возможно, несмежные объекты в непрерывную компоновку, объявив их T t[1]; вместо Т т;
Как теперь решить этот бардак? В стандарте есть принципиально неоднозначное определение оператора sizeof(), которое кажется пережитком того времени, когда, по крайней мере, для каждой архитектуры тип примерно равнялся макету, чего сейчас нет. (Как новое размещение узнает, какой макет создать?)
Применительно к классу результатом [of sizeof()] является количество байтов в объекте этого класса, включая любое заполнение, необходимое для размещения объектов этого типа в массиве. [expr.sizeof] §5.3.3 (2)
Но подождите, количество требуемого отступа зависит от макета, а один тип может иметь более одного макета. Таким образом, мы обязаны добавить немного соли и взять минимум из всех возможных макетов или сделать что-то столь же произвольное.
Наконец, определение массива выиграет от устранения неоднозначности с точки зрения char* арифметики, если это предполагаемое значение. В противном случае применяется ответ на вопрос 1 соответственно.
Несколько замечаний, связанных с уже удаленными ответами и комментариями: noredirect=1&lq=1">Могут ли технически объекты занимать несмежные байты памяти?, несмежные объекты действительно существуют. Кроме того, наивное запоминание подобъекта может сделать недействительными несвязанные подобъекты содержащего объекта, даже для совершенно смежных, тривиально копируемых объектов:
#include <iostream>
#include <cstring>
struct A {
private: int a;
public: short i;
};
struct B : A {
short i;
};
int main()
{
static_assert(std::is_trivial<A>::value , "A not trivial.");
static_assert(not std::is_standard_layout<A>::value , "sl.");
static_assert(std::is_trivial<B>::value , "B not trivial.");
B object;
object.i=1;
std::cout<< object.B::i;
std::memset((void*)&(A&)object ,0,sizeof(A));
std::cout<<object.B::i;
}
// outputs 10 with g++/clang++, c++11, Debian 8, amd64
Следовательно, вполне возможно, что memset в сообщении с вопросом может обнулить a[1].i, так что программа выведет 0 вместо 3.
Есть несколько случаев, когда можно вообще использовать memset-подобные функции с объектами C++. (Обычно деструкторы подобъектов явно не работают, если вы это сделаете.) Но иногда нужно очистить содержимое класса 'почти-POD' в его деструкторе, и это может быть исключением.
person
Heiko Bloch
schedule
05.10.2016
memset
. Структуры C должны работать сmemset
для совместимости, остальное не имеет большого значения. - person Baum mit Augen   schedule 30.09.2016memset()
в вашем примере устанавливает только самое первое целое число в массиве равным 0. Если вы хотите обнулить весь массив, вы должны использоватьmemset(a, 0, sizeof a)
. - person G. Sliepen   schedule 01.10.2016memset
ting сложный объект должен быть UB. - person n. 1.8e9-where's-my-share m.   schedule 04.10.2016