Конструкторы для структур, которые ничего не делают

Изменить: чтобы быть ясным, структура ничего не делает, поскольку в ней нет функций. Я думаю, что у меня создалось впечатление, что я думал, что использовать список инициализаторов и оставить тело конструктора пустым - это проблема.

Скажем, я использую struct для хранения двух значений, и у меня есть конструктор, чтобы я мог создать произвольную структуру следующим образом:

struct twoValues
{
    int x;
    int y;

    twoValues(int x_, int y_):y(y_),x(x_)
    {}
};

someFunction(twoValues(1,2));

Это избавит меня от необходимости делать это:

twoValues anInstance;
anInstance.x=1;
anInstance.y=2;
someFunction(anInstance);

Изменить: вы все правильно, я также мог бы инициализировать следующее:

twoValues anInstance = {1,2};

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

Это плохо и почему? Я бы предпочел продолжить это.

Ответы

Ответ 1

Это зависит от того, для чего используется структура. Как говорили другие, конструктор означает, что класс больше не является POD, и что для него не может использоваться агрегатная инициализация. В частности, вы не может иметь что-то в области пространства имен, например:

TwoValues const table[] =
{
    { 1, 2 },
    { 3, 4 },
    // ...
};

У вас может быть:

TwoValues const table[] =
{
    TwoValues(  1, 2  ),
    TwoValues(  3, 4  ),
    // ...
};

но он более подробен и предполагает динамическую инициализацию, которая может приводят к порядку проблем с инициализацией.

С другой стороны, без конструктора вы не можете создавать временные экземпляры "на лету". Вместо:

extern void f( TwoValues const& );
//  ...

f( TwoValues( 1, 2 ) );

вам нужно написать:

extern void f( TwoValues const& );
//  ...

TwoValues tmp = { 1, 2 };
f( tmp );

Если объект динамически распределяется, это еще хуже, так как вы либо необходимо сначала выделить, затем инициализировать или создать временную выше, а затем напишите new TwoValues( tmp ) и используйте неявную копию конструктор.

Вы должны выбрать. В зависимости от того, для какой структуры используется, один или другой будет предпочтительнее; с одной стороны, у меня много структур, которые используются исключительно в статических таблицах и преднамеренно не имеют конструктор (и содержат только типы, которые поддерживают статические инициализация), и использовать их для настройки кода. С другой У меня также есть много структур, которые являются внутренними для класса, строки Node в дереве или графе; они почти всегда имеют конструктор, чтобы облегчить их создание на лету. Нет "правильный" ответ, не зная о роли структуры в вашем приложение.

Ответ 2

Объявление пустого конструктора имеет побочные эффекты.

Несмотря на то, что ваш конструктор имеет пустое тело, он по-прежнему считается конструктором, и поэтому некоторые свойства объекта будут потеряны - например, объект POD.

В некоторых случаях требуется использование простых типов данных данных, что может сделать нежелательным делать то, что вы сделали без какой-либо конкретной причины.

Узнайте больше об инициализации без конструктора defult в следующем разделе.


&& & && & & &;

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

struct Obj {
  int x, y;
};

Obj a = {1,3}; /* a.x = 1, a.y = 2 */

Недостатком конструктора не является то, что вы не можете инициализировать объект с помощью = { ... } при определенных обстоятельствах при написании С++ 03.

С++ 11 исправляет это для вас, см. следующий раздел для соответствующих примеров.


В С++ 11 инициализация с помощью фигурных скобок (= { ... }) получила повышенную функциональность.

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

struct DoubleBoth {
  DoubleBoth (int x, int y)
    : x(x*2), y(y*2) 
  {}  

  int x, y;
};

Ниже приведенные ниже фрагменты были незаконными до С++ 11:

DoubleBoth a = {1,2}; /* a.x = 2, a.y = 4 */

struct Wrapper {
  Wrapper ()
    : value {3,4}
  {}

  DoubleBoth value;
};

void func (DoubleBoth v = {1,2}) {  // c++11 only
  ...
}

func ({4,5}); // c++11 only, c++03 requires `DoubleBoth obj (0,1); func (obj);`

Ответ 3

Вы остановили twoValues как POD и не допустили, чтобы экземпляры структуры были инициализированы по умолчанию или инициализированы значением, которые часто являются желательными свойствами. Лично я бы предпочел иметь свободную функцию для создания временных экземпляров, если вам нужен простой подход С++ 03.

например.

twoValues makeTwoValues(int x_, int y_)
{
    twoValues tmp = { x_, y_ };
    return tmp;
}

void f() {
    someFunction(makeTwoValues(1,2));
}

например. инициализация элемента типа twoValues

class X {
    twoValues tv;
public:
    X(int x, int y) : tv(makeTwoValues(x, y)) {}
};

Ответ 4

Это гораздо безопаснее иметь такой конструктор, чем инициализировать его списком.

Когда вы инициализируетесь со списком:

twoValues anInstance = {1, 2};

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

Если другой программист добавляет другой член или сортирует элементы по алфавиту, он не будет работать правильно.

Наличие конструктора, который присваивает значения правильному члену NAME, намного безопаснее.

Ответ 5

Возможно, потому что вы можете его инициализировать следующим образом:

twoValues anInstance = {1, 2};

Однако без конструктора вы не можете инициализировать anInstance в другом списке инициализаторов структуры в С++ 03. Например:

struct Bar {
  twoValues v_;
  Bar() : v_(1,2) {} // error!
  Bar() { v_ = {1,2}; } // have to assign value in constructor body
  Bar() : v_{1,2} {} // OK in C++11
};

поэтому на самом деле конструктор что-то делает, и он действительно служит очень полезной цели в С++ 03. Это меньше проблем в С++ 11.

Ответ 6

Нет ничего плохого в этом конструкторе.

Кроме того, он делает что-то, он влияет на значения в x и y, что я и ожидал от такого конструктора.

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

Ответ 7

Конструктор делает структуру не-POD, которая может быть нежелательна в некоторых случаях.

Если ваша структура не имеет конструктора, то ваша структура будет POD 1 и вам будет разрешено инициализировать следующим образом:

twoValues anInstance = {1,2}; //C++03 and C++11 both!
twoValues anInstance {1,2};   //C++11 only

которые хороши.

1. На самом деле есть другие вещи, которые делают структуру не-POD. Так что, потому что ваша структура не имеет конструктора, не обязательно означает, что это POD. Вы хотели бы видеть этот пост, чтобы узнать, что это такое.

Ответ 8

Структуры могут иметь конструкторы, а синтаксис такой же, как для классов в С++. Разница между классом и структурой заключается в том, что члены класса являются закрытыми по умолчанию, а члены структуры по умолчанию являются общедоступными, однако Unions не разрешают конструкторы в структурах. Вы можете сделать конструктор на объединении, хотя.