LINUX.ORG.RU

[c++] инициализация всех членов в конструкторе


0

0

Избавляюсь от вэрнингов вроде «... should be initialized in the member initialization list».

Два вопроса:

1. А действительно ли стоит это делать? Например, есть такой код:

Class SomeClass
{
  double m_a;
  double m_b;
  double m_c;
public:
  SomeClass(a, b):
    m_a(a),
    m_b(b) {  }  // конструктор для "повседневного" применения

  SomeClass() {  } // это для того, чтобы можно было делать vector элементов этого типа

  void calculateC()
  {
    m_c = /* адская формула с участием a и b */;
  }

  double getC () const { return m_c; }
  void setA (double a) { m_a = a; calculateC(); }
  void setB (double b) { m_b = b; calculateC(); }
}

Насколько оправдано здесь инициализировать m_c в SomeClass(a, b) и все переменные в SomeClass()?

2. Каким образом инициализировать «ненужные» в конструкторе члены? Касательно этого примера, как следует делать:

  SomeClass(a, b):
    m_a(a),
    m_b(b),
    m_c() {  }

или

  SomeClass(a, b):
    m_a(a),
    m_b(b),
    m_c(0) {  }
★★★★★

Ответ на: комментарий от zJes

> 1. Нужно, иначе другой порядок вызова и будут удивительные результаты.

Не распарсил как-то я твоё предложение :). Имеешь в виду, что при другом порядке работы с классом начнутся неожиданные странности?

2. или

т.е. второе?

Obey-Kun ★★★★★ ()
Ответ на: комментарий от zJes

> Нужно, иначе другой порядок вызова и будут удивительные результаты.

Порядок вызова конструктор определяется не порядком их следования в списке инициалиазации, а порядком следования их в классе и положения класса в иерархии

namezys ★★★★ ()

1. Хуже от этого точно не будет. Не вылезет потом где-нибудь значение -2478912 или что-то такое.

2. Для POD-типов оба варианта равнозначны. Первый вариант лучше.

undet ()
Ответ на: комментарий от Obey-Kun

1. Да, к примеру, SomeClass cls; cls.setA(); cls.getC(); или SomeClass cls(a, b); cls.getC();
2. Да, второе.

zJes ★★ ()

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

namezys ★★★★ ()
Ответ на: комментарий от zJes

Возможно. Но если это POD, то я и так знаю как он инициализируется. Если это что-то другое, то 0 уже не прокатит.

undet ()
Ответ на: комментарий от namezys

> Порядок вызова конструктор определяется не порядком их следования в списке инициалиазации, а порядком следования их в классе и положения класса в иерархии

Я это знаю, но при чём здесь это?

Obey-Kun ★★★★★ ()

Каким образом инициализировать «ненужные» в конструкторе члены

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

Насколько оправдано здесь инициализировать m_c в SomeClass(a, b) и все переменные в SomeClass()?

все эти поля будут проинициализированы в любом случае; воспользовавшись списком инициализации, ты получишь контроль над тем, как именно это будет сделано

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> все эти поля будут проинициализированы в любом случае

Не правда. втроенные типы не инициализируются

namezys ★★★★ ()
Ответ на: комментарий от namezys

Объясни, что тебя подтолкнуло это написать, я не понял, если честно. :)
Я разве написал про порядок инициализации полей?

zJes ★★ ()

А что насчёт gui-приложений? Тут тоже писать списки инициализации? :)

У меня конкретно здесь всё выглядит так:

MainWindow::MainWindow()
{
    init();
    setCurrentFile("");
}

MainWindow::MainWindow(const QString &fileName)
{
    init();
    loadFile(fileName);
}

void MainWindow::init()
{
    setAttribute(Qt::WA_DeleteOnClose);

    isUntitled = true;

    fieldEdit = new Area;
    scene = new Scene;
    setCentralWidget(fieldEdit);
    fieldEdit->setScene(scene);

    createActions();
    createMenus();
    createToolBars();
    createStatusBar();

    readSettings();

    // connect(fieldEdit->document(), SIGNAL(contentsChanged()),
    //         this, SLOT(documentWasModified()));

    connect(fieldEdit, SIGNAL(cursorPositionChanged(QPointF)), SLOT(cursorPosition(QPointF)));
    connect(fieldEdit, SIGNAL(cursorIsNowOut()), SLOT(cursorPosition()));
    setUnifiedTitleAndToolBarOnMac(true);
}

То есть инициализация идёт в функции init(), как принято во многих местах (например, в google)

Разумеется, идёт куча вэрнингов типа

...: ‘qfgui::MainWindow::fileMenu’ should be initialized in the member initialization list
...: ‘qfgui::MainWindow::exitAct’ should be initialized in the member initialization list

В данном случае следует подавлять вэрнинги?

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun

В данном случае следует подавлять вэрнинги?

нет. конструкторы в списке инициализации, первичная настройка - в init

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

То есть конструктор станет примерно таким:

MainWindow():
    curFile(""),
    isUntitled(1),

    fileMenu(NULL),
    editMenu(NULL),
    helpMenu(NULL),
    fileToolBar(NULL),
    editToolBar(NULL),
    newAct(NULL),
    openAct(NULL),
    saveAct(NULL),
    saveAsAct(NULL),
    closeAct(NULL),
    exitAct(NULL),
    cutAct(NULL),
    copyAct(NULL),
    pasteAct(NULL),
    aboutAct(NULL),
    aboutQtAct(NULL),
    /* и так далее, ещё 15-20 членов */
{
    init(); 
}

Как-то странно смотрится. В хороших проектах правда так делают?

P.S.: все члены Act'ы, виджеты и т.п. у меня представлены как указатели, в инициализации делается что-то типа

    openAct = new QAction(tr("&Open..."), this);
    openAct->setShortcuts(QKeySequence::Open);
    openAct->setStatusTip(tr("Open an existing file"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun

В хороших проектах правда так делают?

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

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> здравый смысл тебе в этом случае что подсказывает?

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

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun

> хотя принимая во внимание свой опыт,

имеется в виду отсутствие опыта

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun

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

zJes ★★ ()
Ответ на: комментарий от Obey-Kun

Ничего общего :) Если чё. :)
Инит там есть, но у него другая функция, именно та что написал jtootf - первичная настройка.

zJes ★★ ()
Ответ на: комментарий от Obey-Kun

ну разве что createToolBox(), createStatusBar() и прочее распихано по соответствующим файлам (kpMainWindow_StatusBar.cpp, kpMainWindow_Tools.cpp)...

Obey-Kun ★★★★★ ()
Ответ на: комментарий от Obey-Kun

потому, что там используется d = new BlahPrivate() - со своим конструктором и тд. Полей - контролов нет в классе окна. Считай что они формально инициализируются в другом месте.
Хотя скорее всего я и не прав.

zJes ★★ ()
Ответ на: комментарий от jtootf

> семантически - инициализируются. мусором

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

anonymous ()
Ответ на: комментарий от jtootf

> вышла бы - сказал бы

char* ptr;
printf( ptr );

т.е. тут ptr тоже инициализирована? странно, что компилятор думает по другому ;)

Using uninitialized memory 'ptr': Lines: 6, 7
String 'ptr' might not be zero-terminated: Lines: 6, 7
Uninitialized local variable 'ptr' used

lester ★★★★ ()
Ответ на: комментарий от lester

это вопрос терминологии; я имею в виду, что в C++ не существует переменных без значения - любая созданная переменная будет каким-то значением инициализирована. в случае POD-типов (с некоторыми уточнениями) инициализирована она будет мусором

и компилятор не думаетпо-другому, он просто использует наиболее читаемую форму предупреждения; корректней было бы - plain variable wasn't initialized explicitly

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> это вопрос терминологии; я имею в виду, что в C++ не существует переменных без значения - любая созданная переменная будет каким-то значением инициализирована. в случае POD-типов (с некоторыми уточнениями) инициализирована она будет мусором

Какая инициализация мусором? Ознакомься со стандартом языка С++, прежде чем говорить о терминологии!

anonymous ()
Ответ на: комментарий от anonymous

Initialization in computing, is the setting (or «formatting») of a variable to some initial value, either by statically embedding the value at compile time, or else by assignment at run time

ты по собственным ссылкам не ходишь? или английского не знаешь?

ты создал переменную, но явно её не проинициализировал. с точки зрения C++ это не ошибка (хотя современные компиляторы warning тебе выдадут), т.к. переменная плоского типа по созданию будет проинициализирована мусором - вследствие низкоуровневости языка. если бы любая переменная в C++ неявно инициализировалась нулём, ничего бы с технической точки зрения не изменилось

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> если бы любая переменная в C++ неявно инициализировалась нулём, ничего бы с технической точки зрения не изменилось

по-моему кто-то запутался в терминологии, что значит с «технической точки зрения»? как раз с этой точки зрения разница будет большая - т.к. выполнялись бы явные действия для той самой инициализации

lester ★★★★ ()
Ответ на: комментарий от anonymous

Объясни мне как можно переменную _инициализировать_ мусором?

void f()
{
    int i;

    std::cout << i << std::endl;
}

мы объявили переменную, но никакой явной инициализации не произвели; тем не менее, этот код не является ошибочным - он скомпилируется и даже выполнится. что будет выведено на экран? мусор

jtootf ★★★★★ ()
Ответ на: комментарий от lester

по-моему кто-то запутался в терминологии

нет ничего сложнее, чем объяснять очевидные для себя вещи

разница будет большая

в обоих случаях значение у переменной будет; как именно оно будет связано с переменной - неважно (можно представить подлежащую машину, на которой инициализация нулём будет требовать меньше действий, чем инициализация мусором, например)

выполнялись бы явные действия для той самой инициализации

с точки зрения программиста они будут неявными. если компилятор сам выдаёт переменной такое начальное значение - это определённо implicit-действие

jtootf ★★★★★ ()
Ответ на: комментарий от anonymous

Википедия: «Вопросительный знак (?) — знак препинания, ставится обычно в конце предложения для выражения вопроса...»

где там сказано, что их можно ставить три штуки подряд?

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

> нет ничего сложнее, чем объяснять очевидные для себя вещи

особенно, если ты их придумал сам ;)

в обоих случаях значение у переменной будет


а кто-то спорил? анонимус уже кидал ссылку на понятие инициализации

с точки зрения программиста они будут неявными


с «технической точки зрения»(с) они будут и значит разница есть

lester ★★★★ ()
Ответ на: комментарий от lester

а кто-то спорил?

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

с «технической точки зрения»(с) они будут и значит разница есть

писали бы мы на ассемблере - было бы это существенно

jtootf ★★★★★ ()
Ответ на: комментарий от jtootf

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

Возвращаемся к плюсам. Когда ты определяешь переменную компилятор выделяет под нее блок памяти и больше ничего с ней не делает! И никаких значений он ни на этапе компиляции ни в рантайме туда просто так не записывает! А раз никто никаких значений не задавал зн-т никакой инициализации нет!

anonymous ()
Ответ на: комментарий от jtootf

кажется спорить бесполезно :) ну значит давай останемся каждый при своем

lester ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.