Конструктор и цикл
От: pasenger  
Дата: 02.10.07 14:18
Оценка:
Есть ли разница с точки зрения эффективности между следующими вариантами и почему?
for(int i = 0; i < 10; ++i)
{
  SomeClass sc(i);
}

SomeClass sc;
for(int i = 0; i < 10; ++i)
{
  sc.SomeClass::SomeClass(i);
}
Re: Конструктор и цикл
От: Константин Л. Франция  
Дата: 02.10.07 14:40
Оценка: +1
Здравствуйте, pasenger, Вы писали:

[]

P>SomeClass sc;

P>for(int i = 0; i < 10; ++i)
P>{
P> sc.SomeClass::SomeClass(i);
P>}
P>[/ccode]

afaik, второй не по стандарту и компилится только vc 7.1
Re[2]: Конструктор и цикл
От: Smal Россия  
Дата: 02.10.07 14:47
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, pasenger, Вы писали:


КЛ>[]


P>>SomeClass sc;

P>>for(int i = 0; i < 10; ++i)
P>>{
P>> sc.SomeClass::SomeClass(i);
P>>}
P>>[/ccode]

КЛ>afaik, второй не по стандарту и компилится только vc 7.1

И деструктор во втором случае вызывается только один раз.
С уважением, Александр
Re: Конструктор и цикл
От: Awaken Украина  
Дата: 02.10.07 15:12
Оценка: -2
Здравствуйте, pasenger, Вы писали:

P>Есть ли разница с точки зрения эффективности между следующими вариантами и почему?


первое бессмысленно, но синтаксически верно.
второе просто неправильно
Re[2]: Конструктор и цикл
От: pasenger  
Дата: 02.10.07 15:30
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>afaik, второй не по стандарту и компилится только vc 7.1


Спасибо. А вы не знаете, существует ли стандартный аналог данной конструкции?
Re[3]: Конструктор и цикл
От: Константин Л. Франция  
Дата: 02.10.07 15:39
Оценка:
Здравствуйте, pasenger, Вы писали:

[]

смотря что надо
Re[2]: Конструктор и цикл
От: Erop Россия  
Дата: 02.10.07 15:43
Оценка:
Здравствуйте, Awaken, Вы писали:

A>первое бессмысленно, но синтаксически верно.

Неправда ваша!
У конструктора могут быть побочные эффекты...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Конструктор и цикл
От: Awaken Украина  
Дата: 02.10.07 16:08
Оценка:
A>>первое бессмысленно, но синтаксически верно.
E>Неправда ваша!
E>У конструктора могут быть побочные эффекты...
данный пример в отрыве от контекста использования — бессмысленный.
Re[4]: Конструктор и цикл
От: pasenger  
Дата: 02.10.07 16:52
Оценка:
Здесь
Автор: pasenger
Дата: 02.10.07
попытался сформулировать.
Re[3]: Конструктор и цикл
От: pasenger  
Дата: 02.10.07 17:02
Оценка:
Здравствуйте, Smal, Вы писали:

S>Здравствуйте, Константин Л., Вы писали:


КЛ>>Здравствуйте, pasenger, Вы писали:


КЛ>>[]


P>>>SomeClass sc;

P>>>for(int i = 0; i < 10; ++i)
P>>>{
P>>> sc.SomeClass::SomeClass(i);
P>>>}
P>>>[/ccode]

КЛ>>afaik, второй не по стандарту и компилится только vc 7.1

S>И деструктор во втором случае вызывается только один раз.
А конструкторов на один больше, чем в первом
Re: Конструктор и цикл
От: ilnar Россия  
Дата: 02.10.07 17:08
Оценка: +1
Здравствуйте, pasenger, Вы писали:

P>Есть ли разница с точки зрения эффективности между следующими вариантами и почему?

P>
P>for(int i = 0; i < 10; ++i)
P>{
P>  SomeClass sc(i);
P>}

P>SomeClass sc;
P>for(int i = 0; i < 10; ++i)
P>{
P>  sc.SomeClass::SomeClass(i);
P>}
P>


извращенство какое!
сделайте просто функцию, выполняющий то что выполняет конструктор.
Re[3]: А что ты хочешь получить?
От: Erop Россия  
Дата: 02.10.07 21:25
Оценка:
Здравствуйте, pasenger, Вы писали:

КЛ>>afaik, второй не по стандарту и компилится только vc 7.1

P>Спасибо. А вы не знаете, существует ли стандартный аналог данной конструкции?

А что тебе надо-то?

Например, можно завести буфер, и там new размещения создавать, а по явному вызову деструктора разрушать объект.
Но зачем это всё?

Почему бы не делать как принято

1) Через временный обхект в цикле:
for( ... ) {
    CMyObj tmp( i );
}


2) Через оператор присваивания:
CMyObj obj
for( ... ) {
    obj = i; // obj = CMyObj( i );
}


3) Через std::swap:
CMyObj obj;
for( ... ) {
    CMyObj tmp( i );
    std::swap( obj, tmp );
}


4) Просто через метод, наконец:
CMyObj obj;
for( ... ) {
    obj.SetNewValue( i );
}


5) Или просто через функцию:
for( ... ) {
    MyFunc( i );
}


Зачем изврат?
В чём твоя цель?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: А что ты хочешь получить?
От: pasenger  
Дата: 03.10.07 05:06
Оценка:
Здравствуйте, Erop, Вы писали:

КЛ>>>afaik, второй не по стандарту и компилится только vc 7.1

P>>Спасибо. А вы не знаете, существует ли стандартный аналог данной конструкции?

E>А что тебе надо-то?


E>Например, можно завести буфер, и там new размещения создавать, а по явному вызову деструктора разрушать объект.

E>Но зачем это всё?

Разумеется, существует множество способов эмулировать поведение данной конструкции.
Меня, в частности, интересует производительность. Скажем, мне не нужно уничтожать объект. Никаких утечек ресурсов это не вызовет (впрочем, при необходимости можно вызвать и деструктор перед повторным вызовом конструктора).
Кроме того, данная конструкция предоставляет определенные удобства. Здесь
Автор: pasenger
Дата: 02.10.07
пример. Или оператор запятая.
Пусть есть классы A и B. Нет возможности написать
A a(i), B b(j);
а так можно написать
a.A::A(i), b.B::B(j);
Этот пример может показаться надуманным, но в может использоваться в цикле, например.
SomeContainer::iterator i = SomeContainer.begin();
A a; B b;
for(a(*i), b(*++i); i != SomeContainer.end(); a.A::A(*++i), b.B::B(*++i))
{
  ...
}


E>Почему бы не делать как принято


E>1) Через временный обхект в цикле:
for( ... ) {
E>    CMyObj tmp( i );
E>}

Да, это работает. Но вроде зовутся лишние деструкторы.

E>2) Через оператор присваивания:
CMyObj obj
E>for( ... ) {
E>    obj = i; // obj = CMyObj( i );
E>}

Оверхед на временные объекты + наложение доп. условий на интерфейс CMyObj. А у нас вовсе необязательно есть возможность менять этот интерфейс.

E>3) Через std::swap:
CMyObj obj;
E>for( ... ) {
E>    CMyObj tmp( i );
E>    std::swap( obj, tmp );
E>}

То же самое: временные объекты + доп. и-фейс

E>4) Просто через метод, наконец:
CMyObj obj;
E>for( ... ) {
E>    obj.SetNewValue( i );
E>}

доп. и-фейс

E>5) Или просто через функцию:
for( ... ) {
E>    MyFunc( i );
E>}

Не совсем понял. Имеется ввиду
CMyObj obj = MyFunc( i )
?


E>Зачем изврат?

E>В чём твоя цель?
Re[5]: А что ты хочешь получить?
От: Erop Россия  
Дата: 03.10.07 06:17
Оценка: 1 (1)
Здравствуйте, pasenger, Вы писали:

P>Здесь
Автор: pasenger
Дата: 02.10.07
пример.

[url=http://www.rsdn.ru/forum/message/2678623.1.aspx
Автор: Erop
Дата: 03.10.07
]Там же[.url] есть и мой ответ

P>
P>SomeContainer::iterator i = SomeContainer.begin();
P>A a; B b;
P>for(a(*i), b(*++i); i != SomeContainer.end(); a.A::A(*++i), b.B::B(*++i))
P>


Методы заведи, да?
Вообще-то если есть вдруг такая ценность, что твои программы должны быть понятными, то лучше всё использовать предсказуемым образом. Каждый изврат очень дорого, так как заставляет нереально напрягать мозг при поддержке. Мало того, если код написан так, что извраты редкость, то при поддержке можно ожидать, что извратов нет или они откомментированны. А иначе везде как по минному полю приходится модифицировать код
E>>Почему бы не делать как принято

Например использовать конструкторы для конструирования объектов. Не для переинициализации, не для модификации, а для конструирования...
А для модификации удобно использовать другие методы, Open например, или присваивания, или std::swap если совсем уж всё плохо

E>>1) Через временный обхект в цикле:
for( ... ) {
E>>    CMyObj tmp( i );
E>>}

P>Да, это работает. Но вроде зовутся лишние деструкторы.
А почему бы их не сделать тривиальными, если они лишние?


E>>2) Через оператор присваивания:
CMyObj obj
E>>for( ... ) {
E>>    obj = i; // obj = CMyObj( i );
E>>}

P>Оверхед на временные объекты + наложение доп. условий на интерфейс CMyObj. А у нас вовсе необязательно есть возможность менять этот интерфейс.

А если объект нельзя менять по его семантике, то зачем это делать в цикле?

E>>3) Через std::swap:
CMyObj obj;
E>>for( ... ) {
E>>    CMyObj tmp( i );
E>>    std::swap( obj, tmp );
E>>}

P>То же самое: временные объекты + доп. и-фейс
Что за "доп интерфейс" такой? И что за "оверхед на доп. объекты"? Речь идёт о лишней памяти?
Ты же всё равно должен звать деструкторы всего того, что ты сконструировал. Так что ты тут зовёшь один лишний конструктор и один лишний деструктор, зато оставляешь себе последнее присвоенное в цикле значение...
При правильной реализации std::swap разумеется...

E>>4) Просто через метод, наконец:
CMyObj obj;
E>>for( ... ) {
E>>    obj.SetNewValue( i );
E>>}

P>доп. и-фейс
Зачем менять объекты, которые нельзя менять по их семантике?
Приведи пример такого объекта, что ли...

E>>5) Или просто через функцию:
for( ... ) {
E>>    MyFunc( i );
E>>}

P>Не совсем понял. Имеется ввиду
CMyObj obj = MyFunc( i )
?

Имеется в виду, что если ты не оставляешь CMyObj за пределами цикла, то код "того самого" конструктора можно переместить в "просто функцию". Ы?

E>>В чём твоя цель?

В чём цель, я так и не понял. Писать через запятую невалидные вызовы конструкторов рвзных типов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: А что ты хочешь получить?
От: Awaken Украина  
Дата: 03.10.07 06:43
Оценка: +1
E>>>В чём твоя цель?
E>В чём цель, я так и не понял. Писать через запятую невалидные вызовы конструкторов рвзных типов?

+1
я тоже нифига не понял. вот что значит нечитабельный код ради сомнительной идеи.
нмв необходимость подобных извращений должна навести на мысль о рефакторинге.
Re[4]: А что ты хочешь получить?
От: Yagg Россия  
Дата: 03.10.07 07:06
Оценка: -1
Здравствуйте, Erop, Вы писали:

E>Почему бы не делать как принято

Если нужно вызвать конструктор для участка памяти, то пользуются placement new
  test t;
  for(int i=0;i<10;++i){
    new (&t) test();
  }
Re[6]: А что ты хочешь получить?
От: pasenger  
Дата: 03.10.07 11:43
Оценка:
Здравствуйте, Erop, Вы писали:

P>>
P>>SomeContainer::iterator i = SomeContainer.begin();
P>>A a; B b;
P>>for(a(*i), b(*++i); i != SomeContainer.end(); a.A::A(*++i), b.B::B(*++i))
P>>


E>Методы заведи, да?

E>Вообще-то если есть вдруг такая ценность, что твои программы должны быть понятными, то лучше всё использовать предсказуемым образом. Каждый изврат очень дорого, так как заставляет нереально напрягать мозг при поддержке. Мало того, если код написан так, что извраты редкость, то при поддержке можно ожидать, что извратов нет или они откомментированны. А иначе везде как по минному полю приходится модифицировать код
E>>>Почему бы не делать как принято
Нечитаемость в данном случае означает использование малораспространенной лексики. Я вобщем не возражаю. Мне и хотелось найти какой-нибудь стандартный аналог.

E>Например использовать конструкторы для конструирования объектов. Не для переинициализации, не для модификации, а для конструирования...

И опять, я ведь не против. Просто мне хотелось бы стандартный, читаемый способ получить описанное поведение. Насколько я понимаю, у плюсов проблема в том, что в синтаксисе зашито смешение объявления и определения. Нет возможности объявить переменную, не определив ее (extern — это что-то не совсем то). И пока не видно стандартных способов определить переменную, не объявляя ее. И это смешение — довольно серьезный косяк. Танцы с временными объектами являются следствием такого смешения (как кажется). Вот грядущая move-семантика должна как-то разрешить это следствие. Но объявление и определение не тождественны. И их смешение все равно вылезет боком.

E>А для модификации удобно использовать другие методы, Open например, или присваивания, или std::swap если совсем уж всё плохо


E>>>1) Через временный обхект в цикле:
for( ... ) {
E>>>    CMyObj tmp( i );
E>>>}

P>>Да, это работает. Но вроде зовутся лишние деструкторы.
E>А почему бы их не сделать тривиальными, если они лишние?
Честно говоря, в данном случае я не возражаю. Видимо наиболее подходящий способ. Я как раз его и опубликовал в начале топика. Вопрос начинался на тему производительности.

E>>>2) Через оператор присваивания:
CMyObj obj
E>>>for( ... ) {
E>>>    obj = i; // obj = CMyObj( i );
E>>>}

P>>Оверхед на временные объекты + наложение доп. условий на интерфейс CMyObj. А у нас вовсе необязательно есть возможность менять этот интерфейс.
E>А если объект нельзя менять по его семантике, то зачем это делать в цикле?

E>>>3) Через std::swap:
CMyObj obj;
E>>>for( ... ) {
E>>>    CMyObj tmp( i );
E>>>    std::swap( obj, tmp );
E>>>}

P>>То же самое: временные объекты + доп. и-фейс
E>Что за "доп интерфейс" такой? И что за "оверхед на доп. объекты"? Речь идёт о лишней памяти?
E>Ты же всё равно должен звать деструкторы всего того, что ты сконструировал. Так что ты тут зовёшь один лишний конструктор и один лишний деструктор, зато оставляешь себе последнее присвоенное в цикле значение...
E>При правильной реализации std::swap разумеется...
Ну может быть, это то что я ищу. А как выглядит правильная реализация? Я в другой ветке
Автор: pasenger
Дата: 03.10.07
написал, какой у меня swap.

E>>>4) Просто через метод, наконец:
CMyObj obj;
E>>>for( ... ) {
E>>>    obj.SetNewValue( i );
E>>>}

P>>доп. и-фейс
E>Зачем менять объекты, которые нельзя менять по их семантике?
E>Приведи пример такого объекта, что ли...
В данный вопрос не хочется углубляться, потому что получиться отдельный, хотя, возможно, и интересный разговор.
Могу попробовать описать, как такая ситуация может возникнуть в реальности. Есть сторонняя библиотека без сорцов, какая-нибудь тяжелая нетривиальная математика, написанная людьми шарящими в математике и не шарящими в плюсах. И авторы библиотеки просто не заморачивались такими вещами, как копирование, "=". И со всем этим надо как-то жить.

E>>>5) Или просто через функцию:
for( ... ) {
E>>>    MyFunc( i );
E>>>}

P>>Не совсем понял. Имеется ввиду
CMyObj obj = MyFunc( i )
?

E>Имеется в виду, что если ты не оставляешь CMyObj за пределами цикла, то код "того самого" конструктора можно переместить в "просто функцию". Ы?
Код конструктора не доступен, например.

E>>>В чём твоя цель?

E>В чём цель, я так и не понял. Писать через запятую невалидные вызовы конструкторов рвзных типов?

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

Вам-то кажется, что все это невообразимо коряво, а мне кажется, что это очень удобно. Но это вкусовщина, которая совершенно не важна.
Re[5]: А что ты хочешь получить?
От: pasenger  
Дата: 03.10.07 11:55
Оценка:
Здравствуйте, Yagg, Вы писали:

E>>Почему бы не делать как принято

Y>Если нужно вызвать конструктор для участка памяти, то пользуются placement new
Y>
Y>  test t;
Y>  for(int i=0;i<10;++i){
Y>    new (&t) test();
Y>  }
Y>

Ага, спасибо. Вот
Автор: Erop
Дата: 02.10.07
говорят, что неопределенное поведение. Хотя тесты и на стеке и в динамической памяти вроде нормально себя ведут. Наверное, возникают проблемы, когда используемый класс каких-нибудь ресурсов наоткрывает, а мы потом затираем все концы новым конструктором.
Re[6]: А что ты хочешь получить?
От: Erop Россия  
Дата: 03.10.07 14:33
Оценка:
Здравствуйте, pasenger, Вы писали:

P>Ага, спасибо. Вот
Автор: Erop
Дата: 02.10.07
говорят, что неопределенное поведение. Хотя тесты и на стеке и в динамической памяти вроде нормально себя ведут. Наверное, возникают проблемы, когда используемый класс каких-нибудь ресурсов наоткрывает, а мы потом затираем все концы новым конструктором.


Точно так, но ещё могут быть и большие проблемы с ресурсами захваченными неявно.
С++ компилятор он же много чего поддерживает, например обработку исключений.
Поэтому автоматические объекты могут где-то регистрироваться, а при разрушении разрегистрироваться, чтобы при пролёте исключения всё сделать корректно.
Кроме того бывают ещё и другие тонкости реализации. Например в случае наличия в объекте виртуальности.
Мало того, вообще-то иногда удобно совместить деструктор и выхыв delete, потому, что, например, бывают виртуальные деструкторы.

Короче говоря компиляторы часто читят и добавляют в деструкторы неявные параметры, которые сообщают контекст в котором разрушается объект (явный вызов delete, разрушеие автоматического объекта, разрушение, явный вызов деструктора). Соотвественно никто не обещал, что эти разные версии деструкторов одинаково хорошо отработают на объектах сконструированных разным образом...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: "А теперь со всей этой фигней мы попытаемся взлететь"
От: pasenger  
Дата: 03.10.07 15:32
Оценка:
Самое удивительное, что после всего, эта штука умудряется как-то работать.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.