Вызвать конструктор напрямую
От: Rothmans  
Дата: 09.12.09 09:46
Оценка:
Привет всем,

Вот давеча натолкнулся (в коде коллег ) на такую вот конструкцию:
сначала стояло:
class SomeClass
{
...
};

SomeClass x[100];
...
for(..)
{
  x[i] = SomeClass();
}

потом видимо при переходе на очередную версию gcc это дело перестало работать (?) и оказалось закомментированным.
На место вышеозначенного кода пришло следующее:
class SomeClass
{
...
};

SomeClass x[100];
...
for(..)
{
  // g++ does not allow the automatic casting
  // x[i] = SomeClass();
  SomeClass sc = SomeClass();
  x[i] = sc;
}

Правда второй вариант тоже не собирается, поскольку у SomeClass не объявлен копирующий конструктор.

Я вообще не каждый день пишу на С++, поэтому тонкости ускользают и/или забываются.
Объясните-ка мне, что автор вообще хотел сказать конструкцией вида x[i] = SomeClass(); ?

Каков смысл в вызове конструктора напрямую без new?
Другой мой коллега утверждает, что
void proc()
{
   SomeClass();
}

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

Какой толк вызывать вне класса его конструктор напрямую без new и без объявления переменной (кроме исполнения самого кода конструктора)?

Спасибо!
Re: Вызвать конструктор напрямую
От: Caracrist https://1pwd.org/
Дата: 09.12.09 10:07
Оценка: 1 (1) -1
Здравствуйте, Rothmans, Вы писали:

R>Привет всем,


R>Вот давеча натолкнулся (в коде коллег ) на такую вот конструкцию:

R>сначала стояло:
R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  x[i] = SomeClass();
R>}
R>

R>потом видимо при переходе на очередную версию gcc это дело перестало работать (?) и оказалось закомментированным.
R>На место вышеозначенного кода пришло следующее:
R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  // g++ does not allow the automatic casting
R>  // x[i] = SomeClass();
R>  SomeClass sc = SomeClass();
R>  x[i] = sc;
R>}
R>

R>Правда второй вариант тоже не собирается, поскольку у SomeClass не объявлен копирующий конструктор.


new (&x[i]) SomeClass();

~~~~~
~lol~~
~~~ Single Password Solution
Re: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 10:08
Оценка: 9 (2)
Здравствуйте, Rothmans, Вы писали:

R>Привет всем,


R>Вот давеча натолкнулся (в коде коллег ) на такую вот конструкцию:

R>сначала стояло:
R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  x[i] = SomeClass();
R>}
R>

R>потом видимо при переходе на очередную версию gcc это дело перестало работать (?) и оказалось закомментированным.
R>На место вышеозначенного кода пришло следующее:
R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  // g++ does not allow the automatic casting
R>  // x[i] = SomeClass();
R>  SomeClass sc = SomeClass();
R>  x[i] = sc;
R>}
R>

R>Правда второй вариант тоже не собирается, поскольку у SomeClass не объявлен копирующий конструктор.

R>Я вообще не каждый день пишу на С++, поэтому тонкости ускользают и/или забываются.

R>Объясните-ка мне, что автор вообще хотел сказать конструкцией вида x[i] = SomeClass(); ?

Он хотел сказать, что не знает С++.
Конструктор там и так вызовется

SomeClass x[100]; // приведет к вызову 100 конструкторов


А тот, кто этот код писал, потом еще раз создавал 100 объектов, и присваивал их значение каждому элементу соответственно.

R>Каков смысл в вызове конструктора напрямую без new?

В С++ нет синтаксической конструкции "вызов конструктора".

R>Другой мой коллега утверждает, что

R>
R>void proc()
R>{
R>   SomeClass();
R>}
R>

R>не только вызовет конструктор, но и _выделит_ память под безымянный объект в стеке и еще и деструктор вызовется при выходе из процедуры.
Так и есть.

R>Какой толк вызывать вне класса его конструктор напрямую без new и без объявления переменной (кроме исполнения самого кода конструктора)?


Толк в создании временного объекта.
void somefunc(SomeClass const & ref)
{
    //... bla-bla
}

somefunc(SomeClass());

или
SomeClass somefunc()
{
    return SomeClass();
}


R>Спасибо!

Re[2]: Вызвать конструктор напрямую
От: Caracrist https://1pwd.org/
Дата: 09.12.09 10:13
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>

C>
C>new (&x[i]) SomeClass();
C>

C>

не плохо было бы ещё деструкторы повызывать... обьекты там уже созданы...
class SomeClass
{
...
};

SomeClass x[100];
... 
// допустим тут решили их пересоздать...
for(..)
{
  x[i]~SomeClass(); //убить старый
  new (&x[i]) SomeClass(); //создать новый по старому адресу
}
~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 10:19
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, Caracrist, Вы писали:


C>>

C>>
C>SomeClass x[100];
C>... 
C>// допустим тут решили их пересоздать...
C>for(..)
C>{
C>  x[i]~SomeClass(); //убить старый
C>  new (&x[i]) SomeClass(); //создать новый по старому адресу
C>}
C>


Лучше так:

for(..)
{
  x[i].reset();
}
Re: Вызвать конструктор напрямую
От: Кодёнок  
Дата: 09.12.09 10:27
Оценка:
Здравствуйте, Rothmans, Вы писали:

R>Каков смысл в вызове конструктора напрямую без new?

R>Какой толк вызывать вне класса его конструктор напрямую без new и без объявления переменной (кроме исполнения самого кода конструктора)?

Объекты в C++ могут создавать в динамической памяти (new) либо быть временными значениями (без new, живут на стеке). Объекты в динамической памяти могут жить пока не удалят, они аналогичны объектам в Java. А временные удаляются при выходе из области видимости, и в другое место передаются копированием, они аналогичны значениям в функциональных языках.
Re[4]: Вызвать конструктор напрямую
От: Caracrist https://1pwd.org/
Дата: 09.12.09 10:37
Оценка:
Здравствуйте, wander, Вы писали:


W>
W>for(..)
W>{
W>  x[i].reset();
W>}
W>



struct Sputnik
{
 int & pogodaSeichas;
 Sputnik(int& pogoda) : pogodaSeichas(pogoda){}
};

class SomeClass : Sputnik
{
 int pogoda[31];
public:
 SomeClass() 
   : Sputnik(pogoda[KakoysegodnyaDen()])
 {
 }
 void reset(); //жду реализации
}
~~~~~
~lol~~
~~~ Single Password Solution
Re[5]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 10:52
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, wander, Вы писали:



W>>
W>>for(..)
W>>{
W>>  x[i].reset();
W>>}
W>>



C>
C>struct Sputnik
C>{
C> int & pogodaSeichas;
C> Sputnik(int& pogoda) : pogodaSeichas(pogoda){}
C>};

C>class SomeClass : Sputnik
C>{
C> int pogoda[31];
C>public:
C> SomeClass() 
C>   : Sputnik(pogoda[KakoysegodnyaDen()])
C> {
C> }
C> void reset(); //жду реализации
C>}
C>


Пример надуманный. Зачем так проектировать?

struct Sputnik
{
 boost::reference_wrapper<int> pogodaSeichas;
 Sputnik(int & pogoda) : pogodaSeichas(pogoda){}
 void reset(int & pogoda) { pogodaSeichas = boost::reference_wrapper<int>(pogoda); } // это то место, за которые ты так уцепился
 
};
// наcледование убрал - инкапсуляцию нарушает и запутывает, лучше так:
class SomeClass
{
 int pogoda[31];
 Sputnik  sp_;
public:
 SomeClass() 
   : sp_(pogoda[KakoysegodnyaDen()])
 {
 }
 void reset()
 {
    sp_.reset(pogoda[KakoysegodnyaDen()]);
 }
}


Только дело ведь не в том, что тут костыль с инициализацией ссылки, а в том, насколько часто такое встречается. Если ты хотел показать, что такие приемы бывают нужны — поздравляю, тебе это удалось. Но нужно ли так делать всегда — большой вопрос.
Re[2]: Вызвать конструктор напрямую
От: rg45 СССР  
Дата: 09.12.09 10:57
Оценка:
Здравствуйте, wander, Вы писали:

R>>Каков смысл в вызове конструктора напрямую без new?

W>В С++ нет синтаксической конструкции "вызов конструктора".

Ну вот, один сказал
Автор: Николай Ивченков
Дата: 05.12.09
, другие подхватили. Не знаю на счет "синтаксической конструкции", но вызов конструктора есть: у любого конструктора есть соглашение о вызове, и этим понятием оперирует стандарт, см., например, п. 3.8/1
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 10:59
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, wander, Вы писали:


R>>>Каков смысл в вызове конструктора напрямую без new?

W>>В С++ нет синтаксической конструкции "вызов конструктора".

R>Ну вот, один сказал
Автор: Николай Ивченков
Дата: 05.12.09
, другие подхватили. Не знаю на счет "синтаксической конструкции", но вызов конструктора есть: у любого конструктора есть соглашение о вызове, и этим понятием оперирует стандарт, см., например, п. 3.8/1


Нет. Тут четко был определен смысл фразы. Человек думал, что здесь не создается объекта, а происходит вызов "как бы функции-конструктора". Это я и имел в виду. Насчет чего подхватили — не понял.
Re[6]: Вызвать конструктор напрямую
От: Caracrist https://1pwd.org/
Дата: 09.12.09 11:00
Оценка: 1 (1)
Здравствуйте, wander, Вы писали:

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

W> Но нужно ли так делать всегда — большой вопрос.


Согласен!
Скажу даже больше, только когда нет выбора и нет возможности сделать редизайн... (а я понял, что у топикастера именно такая ситуация)
~~~~~
~lol~~
~~~ Single Password Solution
Re[3]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 11:02
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, wander, Вы писали:


R>>>Каков смысл в вызове конструктора напрямую без new?

W>>В С++ нет синтаксической конструкции "вызов конструктора".

R>Ну вот, один сказал
Автор: Николай Ивченков
Дата: 05.12.09
, другие подхватили. Не знаю на счет "синтаксической конструкции", но вызов конструктора есть: у любого конструктора есть соглашение о вызове, и этим понятием оперирует стандарт, см., например, п. 3.8/1


Я как-то давно в коде коллеги увидел вот такое:

class SomeClass
{
   int a_;
public:
   SomeClass()
   {
      SomeClass(5);
   }

   SomeClass(int a)
      : a_(a)
   {
   }
};


Понятно о чем я?
Re[4]: Вызвать конструктор напрямую
От: Rothmans  
Дата: 09.12.09 11:07
Оценка:
Да да, wander четко уловил смысл моего вопроса.
Re[7]: Вызвать конструктор напрямую
От: Rothmans  
Дата: 09.12.09 11:11
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, wander, Вы писали:


C>Подключил буст, сделал редизайн... Это не плохо и скорее даже к лучшему, но не всегда доступно.


W>> Но нужно ли так делать всегда — большой вопрос.


C>Согласен!

C>Скажу даже больше, только когда нет выбора и нет возможности сделать редизайн... (а я понял, что у топикастера именно такая ситуация)

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

Спасибо, народ, просветили!
Re[4]: Вызвать конструктор напрямую
От: rg45 СССР  
Дата: 09.12.09 11:14
Оценка:
Здравствуйте, wander, Вы писали:

R>>>>Каков смысл в вызове конструктора напрямую без new?

W>>>В С++ нет синтаксической конструкции "вызов конструктора".

R>>Ну вот, один сказал
Автор: Николай Ивченков
Дата: 05.12.09
, другие подхватили. Не знаю на счет "синтаксической конструкции", но вызов конструктора есть: у любого конструктора есть соглашение о вызове, и этим понятием оперирует стандарт, см., например, п. 3.8/1


W>Нет. Тут четко был определен смысл фразы. Человек думал, что здесь не создается объекта, а происходит вызов "как бы функции-конструктора". Это я и имел в виду. Насчет чего подхватили — не понял.


По сути сказанного тобой я полностью согласен. Что меня удивило, так это точность совпадения твоей фразы с тем, что было совершенно не к месту написано здесь
Автор: Николай Ивченков
Дата: 05.12.09
. Фразы совпадают с точностью до символа, поэтому я невольно решил, что тут не обошлось без повторов. Если я ошибся, приношу извинения.
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 11:18
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, wander, Вы писали:


R>>>>>Каков смысл в вызове конструктора напрямую без new?

W>>>>В С++ нет синтаксической конструкции "вызов конструктора".

R>>>Ну вот, один сказал
Автор: Николай Ивченков
Дата: 05.12.09
, другие подхватили. Не знаю на счет "синтаксической конструкции", но вызов конструктора есть: у любого конструктора есть соглашение о вызове, и этим понятием оперирует стандарт, см., например, п. 3.8/1


W>>Нет. Тут четко был определен смысл фразы. Человек думал, что здесь не создается объекта, а происходит вызов "как бы функции-конструктора". Это я и имел в виду. Насчет чего подхватили — не понял.


R>По сути сказанного тобой я полностью согласен. Что меня удивило, так это точность совпадения твоей фразы с тем, что было совершенно не к месту написано здесь
Автор: Николай Ивченков
Дата: 05.12.09
. Фразы совпадают с точностью до символа, поэтому я невольно решил, что тут не обошлось без повторов.

Прочитал ту ветку — забавно.
R>Если я ошибся, приношу извинения.
Все нормально!
Re[8]: Вызвать конструктор напрямую
От: Rothmans  
Дата: 09.12.09 11:24
Оценка:
Здравствуйте, Rothmans, Вы писали:

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


Так так.. это я погорячился.
Смысл кода очевидно именно в очистке массива (приведении его в исходный вид).
class SomeClass{...};

class MyContainer 
{
...
private:
SomeClass x[100];
public:
void clearX()
...
};
...
void MyContainer::clearX()
{
  for(int i=0; i<100;++i)
  {
    // g++ does not allow the automatic casting
    // x[i] = SomeClass();
    SomeClass sc = SomeClass();
    x[i] = sc;
  }
}
Re[9]: Вызвать конструктор напрямую
От: wander  
Дата: 09.12.09 11:28
Оценка:
Здравствуйте, Rothmans, Вы писали:

R>Здравствуйте, Rothmans, Вы писали:


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


R>Так так.. это я погорячился.

R>Смысл кода очевидно именно в очистке массива (приведении его в исходный вид).
R>
R>class SomeClass{...};

R>class MyContainer 
R>{
R>...
R>private:
R>SomeClass x[100];
R>public:
R>void clearX()
R>...
R>};
R>...
R>void MyContainer::clearX()
R>{
R>  for(int i=0; i<100;++i)
R>  {
R>    // g++ does not allow the automatic casting
R>    // x[i] = SomeClass();
R>    SomeClass sc = SomeClass();
R>    x[i] = sc;
R>  }
R>}
R>


С этого и надо было начинать. А то ж непонятно. В таком случае пользуйся советом Caracrist`a или моим на его пост ответом.
Re: Вызвать конструктор напрямую
От: M16_rage  
Дата: 09.12.09 11:36
Оценка:
Здравствуйте, Rothmans, Вы писали:

R>Привет всем,


R>Вот давеча натолкнулся (в коде коллег ) на такую вот конструкцию:

R>сначала стояло:
R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  x[i] = SomeClass();
R>}
R>

R>потом видимо при переходе на очередную версию gcc это дело перестало работать (?) и оказалось закомментированным.
Версии компиляторов стремятся к несовместимости (по разным причинам).
При переходе все и проявляется..

R>На место вышеозначенного кода пришло следующее:

R>
R>class SomeClass
R>{
R>...
R>};

R>SomeClass x[100];
R>...
R>for(..)
R>{
R>  // g++ does not allow the automatic casting
R>  // x[i] = SomeClass();
R>  SomeClass sc = SomeClass();
R>  x[i] = sc;
R>}
R>

R>Правда второй вариант тоже не собирается, поскольку у SomeClass не объявлен копирующий конструктор.

Зачем копировать?
  // или обойтись без копирования,
  // дополняя парой функций (де)инициализации класс SomeClass:
  // int  Init() {/*Do init*/}
  // void Exit() {/*Do exit*/} // в деструкторе не забыть вызвать
  // тогда
  x[i].Init();


R>Я вообще не каждый день пишу на С++, поэтому тонкости ускользают и/или забываются.

R>Объясните-ка мне, что автор вообще хотел сказать конструкцией вида x[i] = SomeClass(); ?

R>Каков смысл в вызове конструктора напрямую без new?

R>Другой мой коллега утверждает, что
R>
R>void proc()
R>{
R>   SomeClass();
R>}
R>

R>не только вызовет конструктор, но и _выделит_ память под безымянный объект в стеке и еще и деструктор вызовется при выходе из процедуры.

R>Какой толк вызывать вне класса его конструктор напрямую без new и без объявления переменной (кроме исполнения самого кода конструктора)?

Служебные операции захвата (или прочее) объекта должны быть выполнены при входе и освобождены при выходе. Стековая переменная для этих целей подходит, указатель на динамическую память подходит только в стековой оболочке (врепере). При этом, обращение к переменной, обычно, не нужно.
New — медленная функция, стэк быстрее работает.

R>Спасибо!
Re[9]: Вызвать конструктор напрямую
От: Юрий Жмеренецкий ICQ 380412032
Дата: 09.12.09 12:59
Оценка:
Здравствуйте, Rothmans, Вы писали:

R>Смысл кода очевидно именно в очистке массива (приведении его в исходный вид).

R>
R>class SomeClass{...};

R>class MyContainer 
R>{
R>...
R>private:
R>SomeClass x[100];
R>public:
R>void clearX()
R>...
R>};
R>...
R>void MyContainer::clearX()
R>{
R>  for(int i=0; i<100;++i)
R>  {
R>    // g++ does not allow the automatic casting
R>    // x[i] = SomeClass();
R>    SomeClass sc = SomeClass();    // 1
R>    x[i] = sc;                     // 2
R>  }
R>}
R>


Здесь есть одна потенциальная проблема — если в точках 1 и 2 возможна генераци исключений, то реализация функции 'clearX' не удовлетворяет 'strong exception guarantee' т.к. алгоритм ее работы заключается в изменении объектов из некоторого диапазона 'по месту'. Если операция изменения (или любая ее часть) приведет к генерации исключения, то содержимое массива будет представлять собой совокупность 'очищенных' элементов и элементов со старыми значениями (кроме исключения в точке 1 при первой итерации). Полноценный откат к состоянию, в котором находился объект типа 'MyContainer' до вызова 'clearX' при такой реализации невозможен, т.к. некоторые значения будут потеряны.

Проблема решается посредством создания временного объекта-массива, члены которого инициализированы неким образом и выполнении nothrow swap'a с объектом-членом (или явного почленного swap'a для подобъектов массива).
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.