Как инициализировать структуру на 0 в C ++ - PullRequest
0 голосов
/ 16 апреля 2020

Вот связанный C ответ, который не работает (как нулевой инициализатор для структуры) в C ++: Инициализация структуры в 0 . Вот одно из представленных решений:

myStruct _m1 = {0}; 

Это отлично работает в C, но не работает в C ++. :(:

ошибка: невозможно инициализировать подобъект члена типа 'myScope :: MyStruct' значением r типа 'int'`.

Как вы обнуляете -инициализировать структуру в C ++?

Связано:

  1. Инициализация структуры в 0 в C: Инициализация структуры в 0
  2. Обновление: (смежный, но НЕ дублирующий вопрос, который также оказывается очень полезным) Инициализация с пустыми фигурными скобками

Модам, голосующим за закрытие этого вопроса:

Мой вопрос не является дубликатом этого другого вопроса ( Инициализация с пустыми фигурными скобками ), так как этот другой вопрос не касается различных способов инициализации структуры в C ++ и почему C путь не работает, скорее, они спрашивают , почему ключевое слово C ++ explicit нарушает один из методов инициализации . Два разных вопроса. Не дублируется.

Ответы [ 3 ]

1 голос
/ 30 апреля 2020

Обычно это невозможно. Класс может не обеспечивать доступ ко всем членам, и в этих случаях лучшее, что вы можете сделать, это значение инициализировать оно, которое даст вам версию этого класса по умолчанию.

1 голос
/ 01 мая 2020

Объектам в C ++ предоставляется возможность управлять значениями любых подобъектов в них. Таким образом, в C ++ нет механизма, который заставлял бы инициализацию с нуля для любого объекта в целом .

Объекты без предоставленных пользователем конструкторов или инициализаторов членов по умолчанию могут в go инициализация с нуля * в двух случаях: если переменная объявлена ​​static или если объект инициализируется значением. Существует несколько синтаксисов, которые будут вызывать инициализацию значения объекта, включая T(), T{} и T t = {};, где это применимо.

Но кроме этого, если создатель типа объекта не хочет, чтобы оно было инициализировано нулями, тогда вы не можете навязать это объекту. Вы можете запросить инициализацию значения или инициализацию по умолчанию, но то, вызовет ли один из них инициализацию нуля, зависит от типа.

0 голосов
/ 16 апреля 2020

Я понял: для компиляции просто удалите ноль:

myStruct _m1 = {};

Теперь он компилируется. Тем не менее, Я провел несколько тестов, чтобы проверить некоторые вещи , и это НЕ инициализирует все элементы структуры в ноль! Скорее, он инициализирует структуру со значениями по умолчанию.

Предполагается, что у вас есть такая структура:

typedef struct
{
    int num1 = 100;
    int num2 = -100;
    int num3;
    int num4 = 150;
} data_t;

Примечание: typedef выше - это перенос с того времени, когда я тестировал этот материал в C вместо C ++ (хотя значения структуры по умолчанию недопустимы в C, конечно). Для C ++ это предпочтительнее:

struct data_t
{
    int num1 = 100;
    int num2 = -100;
    int num3;
    int num4 = 150;
};

Поэтому, пожалуйста, игнорируйте его везде, где я без необходимости использую typedef для определения структур ниже.

В любом случае , если я объявлю одну из вышеуказанных data_t структур, а затем сделаю следующее:

data_t d2 = {};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
       d2.num1, d2.num2, d2.num3, d2.num4);

... вывод будет:

d2.num1 = 100
d2.num2 = -100
d2.num3 = 0
d2.num4 = 150

И я даже не обязательно, если d2.num3 равно нулю, потому что оно было инициализировано в ноль или потому что оно оставлено неинициализированным, а в этой ячейке памяти оказалось ноль.

Как объяснено здесь: https://en.cppreference.com/w/cpp/language/zero_initialization, вы также можно сделать это:

myStruct _m1{};

В приведенном выше примере этот код:

data_t d2{};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
       d2.num1, d2.num2, d2.num3, d2.num4);

... будет выдавать вывод, идентичный тому, что я показал выше.

Даже в тех случаях, когда установка структуры на = {0} работает, например, так:

// Does NOT do what I expected! Only sets the FIRST value in the struct to zero! 
// The rest seem to use default values.
data_t d3 = {0};
printf("d3.num1 = %i\nd3.num2 = %i\nd3.num3 = %i\nd3.num4 = %i\n\n",
       d3.num1, d3.num2, d3.num3, d3.num4);

... результат все равно не тот, который я ожидал, так как он только устанавливает first значение до нуля! (Я не понимаю, почему):

d3.num1 = 0
d3.num2 = -100
d3.num3 = 0
d3.num4 = 150

В C стиле массивах , однако (НЕ структурирует), эта семантика работает нормально. Обратитесь к этому ответу здесь ( Как инициализировать все члены массива одним и тем же значением? ). Поэтому в следующих строках все элементы массива C устанавливаются на ноль при использовании C ++:

uint8_t buffer[100] = {0}; // sets all elements to 0 in C OR C++
uint8_t buffer[100] = {};  // sets all elements to 0 in C++ only (won't compile in C)

Итак, после долгих экспериментов выглядит подобно следующим нескольким способам, это ЕДИНСТВЕННЫЕ способы нулевой инициализации структуры, PERIOD. Если вы знаете по-другому, пожалуйста, прокомментируйте и / или оставьте свой собственный ответ здесь.

Единственные возможные способы инициализации нуля структуры в C ++.

  1. Будьте явными:

    // C-style typedef'ed struct
    typedef struct
    {
        int num1 = 100;
        int num2 = -100;
        int num3;
        int num4 = 150;
    } data_t;
    
    // EXPLICITLY set every value to what you want!
    data_t d1 = {0, 0, 0, 0};
    // OR (using gcc or C++20 only)
    data_t d2 = {.num1 = 0, .num2 = 0, .num3 = 0, .num4 = 0}
    
  2. Используйте memset() для принудительной установки всех байтов на ноль:

    data_t d3;
    memset(&d3, 0, sizeof(d3));
    
  3. Установите все значения по умолчанию на ноль в первую очередь:

    // C-style typedef'ed struct
    typedef struct
    {
        int num1 = 0;
        int num2 = 0;
        int num3 = 0;
        int num4 = 0;
    } data_t;
    
    // Set all values to their defaults, which are zero in
    // this case
    data_t d4 = {};
    // OR
    data_t d5{}; // same thing as above in C++
    
    // Set the FIRST value only to zero, and all the rest
    // to their defaults, which are also zero in this case
    data_t d6 = {0};
    
  4. Написать конструктор для структуры C ++

    // 1. Using an initializer list
    struct data
    {
        int num1;
        int num2;
        int num3;
        int num4;
    
        data() : 
            num1(0),
            num2(0),
            num3(0),
            num4(0) {}
    };
    
    data d7; // all values are zero
    
    // OR: 2. manually setting the values inside the constructor
    struct data
    {
        int num1;
        int num2;
        int num3;
        int num4;
    
        data()
        {
            num1 = 0;
            num2 = 0;
            num3 = 0;
            num4 = 0;
        }
    };
    
    data d8; // all values are zero
    
  5. Использовать структуру без значений по умолчанию, и сделайте из него созданный вами объект static

    tpedef struct
    {
        int num1;
        int num2;
        int num3;
        int num4;
    } data_t;
    
    // `static` forces a default initialization of zero for each
    // value when no other default values are set
    static data_t d9;
    
  6. Итак, если у вас есть структура с ненулевыми значениями по умолчанию, и вы хотите обнулить все значения, вы должны сделать это ТОЧНО! Вот еще несколько способов:

    // 1. Have a `constexpr` copy of the struct that you use to
    // reset other struct objects. Ex:
    
    struct data
    {
        int num1 = 1;
        int num2 = 7;
        int num3 = -10;
        int num4 = 55;
    };
    
    constexpr data DATA_ALL_ZEROS = {0, 0, 0, 0};
    
    // Now initialize d13 to all zeros using the above `constexpr` struct 
    // object
    data d13 = DATA_ALL_ZEROS; 
    
    
    // OR 2. Use a `zero()` member function to zero the values:
    
    struct data
    {
        int num1 = 1;
        int num2 = 7;
        int num3 = -10;
        int num4 = 55;
    
        zero()
        {
            num1 = 0;
            num2 = 0;
            num3 = 0;
            num4 = 0;
        }
    };
    
    data d14;
    d14.zero();
    

Большой вывод здесь заключается в том, что ни один из них: data_t d{}, data_t d = {} и data_t d = {0}, фактически устанавливают всех членов структуры в ноль!

  1. data_t d{} устанавливает все значения по умолчанию, определенные в структуре.
  2. data_t d = {} также устанавливает все значения по умолчанию.
  3. И data_t d = {0} устанавливает только ПЕРВОЕ значение на ноль, а все остальные значения по умолчанию.

SO, BE EXPLICIT !

Обратите внимание, что вышеприведенные ключевые выводы, которые я написал, как представляется, противоречат этой документации , поэтому я побудил меня задать этот дополнительный вопрос, указанный ниже как ссылка № 1, который оказался ОЧЕНЬ полезным для моего понимания!

Ссылки:

  1. [ НАИБОЛЕЕ ПОЛЕЗНО ] Почему инициализация структуры C ++ для `= {0}` не устанавливает все ее члены в 0?
  2. [ОЧЕНЬ ПОЛЕЗНО]
    1. https://en.cppreference.com/w/cpp/language/zero_initialization
    2. https://en.cppreference.com/w/cpp/language/aggregate_initialization
    3. https://en.cppreference.com/w/cpp/language/value_initialization
  3. [ОЧЕНЬ ПОЛЕЗНО] Инициализация всех членов массива (не struct) к одному и тому же значению:
    1. Как инициализировать все члены массива одним и тем же значением?
    2. [g cc only] Как инициализировать все элементы массива одинаковыми значениями?
  4. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/struct_initialization.cpp
    1. Клонируйте этот репозиторий и выполните код самостоятельно с помощью cpp/run_struct_initialization.sh

Related:

  1. Инициализация значений по умолчанию в структуре
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...