Re[3]: Вызов конструктора копирования для участка памяти.
От: Андрей Тарасевич Беларусь  
Дата: 10.05.05 03:09
Оценка: +1 -1 :))
Здравствуйте, Denich, Вы писали:

D>Здравствуйте, c-smile, Вы писали:


D>

D>>>Есть участок памяти, есть экземпяр объекта.
D>>>Каким образом можно сконструировать объект — копию заданного объекта
D>>>в заданном участке памяти (через конструктор копирования)?
CS>>Примерно так
D>

CS>> void *p = ...;
CS>> myclass * myclass_dst_object_p = new(p) myclass( myclass_src_object );
D>


D>Спасибо! Действительно именно так. Только с маленькой оговоркой -

D>оператор new должен быть перегруженным.

Разумеется. Оператор 'new' для вышеприведенного случая перегружен в стандартной библиотеке языка С++.
Best regards,
Андрей Тарасевич
Re[4]: Вызов конструктора копирования для участка памяти.
От: MaximE Великобритания  
Дата: 10.05.05 22:35
Оценка: 1 (1) +2
On Tue, 10 May 2005 22:37:17 +0400, Denich <41566@users.rsdn.ru> wrote:

> Здравствуйте,

>
> Подведу предварительный итог.
>
> По поводу передачи аргументов в функцию оператора new
> в MSDN говориться следующее:
>
>
> new-expression:
> [::] new [placement] new-type-name [new-initializer]
> [::] new [placement] ( type-name ) [new-initializer]
>
> И далее
>
> placement
>     Provides a way of passing additional arguments
>     if you overload new.
>     (Создает возможность передачи дополнительных аргументов
>      в случае если вы перегружаете оператор new)
>


Мой друг, в MSDN столько херни про С++ понаписано...

> Примерно то же самое говорится и в ISO стандарте от 98 года.


Стандарт явно запрещает перегружать placement new с сигнатурами void* operator new(std::size_t size, void* ptr) throw(); void* operator new[](std::size_t size, void* ptr) throw();, и соответствующие им формы delete. Ссылка на стандарт уже приводилась: http://rsdn.ru/forum/?mid=1162685
Автор: MaximE
Дата: 10.05.05


> И нигде ни слова нет про то что new(void *ptr) обозначает

> конструирование без распределения памяти.

Стандарт писан юниксовыми перцами, и читать его надо как подабает читать юниксовые писания:

http://www.faqs.org/docs/artu/ch18s02.html#id3001522

Where most other software documentation tends to to oscillate between incomprehensibility and oversimplifying condescension, classic Unix documentation is written to be telegraphic but complete. It does not hold you by the hand, but it usually points in the right direction. The style assumes an active reader, one who is able to deduce obvious unsaid consequences of what is said, and who has the self-confidence to trust those deductions.

Unix programmers tend to be good at writing references, and most Unix documentation has the flavor of a reference or aide memoire for someone who thinks like the document-writer but is not yet an expert at his or her software. The results often look much more cryptic and sparse than they actually are. Read every word carefully, because whatever you want to know will probably be there, or deducible from what's there. Read every word carefully, because you will seldom be told anything twice.


Cтандарт про placement new

18.4.1.3 Placement forms [lib.new.delete.placement]
1 These functions are reserved, a C++ program may not define functions that displace the versions in the
Standard C++ library (17.4.3).
void* operator new(std::size_t size, void* ptr) throw();
2 Returns: ptr.
3 Notes: Intentionally performs no other action.


Здесь obvious unsaid consequences — это то, что ключевое слово new вызывает соответствующую форму operator new (ключевое слово new и operator new — разные вещи) и затем вызывает конструктор объекта. Остается догадаться, что если operator new "Returns: ptr" и "Intentionally performs no other action", то остается только вызов конструктора.

> Хотя у Страуструпа подобное описание есть с пометкой что

> для использования данной конструкции надо включать файл
> <new>, являющийся, кстати говоря, частью Стандартной
> библиотеки.
>
> Возможно у меня старая документация, хотя по правде говоря,
> думается мне, что причина умолчания здесь в том что стандарт
> Си++ не подразумевает наличие Стандартной библиотеки .

Стандартные библиотеки C и C++ — часть стандарта С++. Скорее, стандарт не подразумевает их отсутствия.

1.1 Scope [intro.scope]
...
2 C++ is a general purpose programming language based on the C programming language as described in ISO/IEC 9899:1990 Programming languages – C (1.2). In addition to the facilities provided by C, C++ provides additional data types, classes, templates, exceptions, namespaces, inline functions, operator overloading, function name overloading, references, free store management operators, and additional library facilities.


> Хоршо. С этим я разобрался. Спасибо за помощ. НО!

> После создания объекта его еще нужно уничтожить.
> Как пишет Страуструп основной способ уничтожения подобного
> объекта это явный вызов деструктора.
> В принципе все просто вызываем Obj->~MyClass(); и все.
> Но вот когда речь доходит до шаблонов тут начинаются
> проблемы.
>
> Допустим объявление класса содержит template<class T>
> и распределяемый объект имеет обобщенный тип "Т". Тогда
> конструктор вызываем так — new(ptr) T;
>
> Как вызвать деструктор для подобного объекта?
>
> ptr->~T(); не проходит и по идее не должно.

Это и есть синтаксически правильный способ вызова деструктора, если ptr имеет тип T*. В противном случае, тебе нужно скастить ptr к T*.

> В файле <new> есть перегруженный delete для этого случая,

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

Эти форма delete может быть только вызвана и вызывается компилятором, когда конструктор объекта кидает исключение.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[2]: Вызов конструктора копирования для участка памяти.
От: Denich Филиппины  
Дата: 10.05.05 01:31
Оценка: -2
Здравствуйте, c-smile, Вы писали:

D>>Есть участок памяти, есть экземпяр объекта.
D>>Каким образом можно сконструировать объект — копию заданного объекта
D>>в заданном участке памяти (через конструктор копирования)?
CS>Примерно так

CS> void *p = ...;
CS> myclass * myclass_dst_object_p = new(p) myclass( myclass_src_object );


Спасибо! Действительно именно так. Только с маленькой оговоркой —
оператор new должен быть перегруженным.
Пример из MSDN:

// This will call ::operator new(size_t, char*, int).
A* pa2 = new(__FILE__, __LINE__) A(20);


Денис
Re[3]: Вызов конструктора копирования для участка памяти.
От: Кодт Россия  
Дата: 10.05.05 09:47
Оценка: 2 (1)
Здравствуйте, Denich, Вы писали:

D>Спасибо! Действительно именно так. Только с маленькой оговоркой -

D>оператор new должен быть перегруженным.
D>Пример из MSDN:
D>// This will call ::operator new(size_t, char*, int).
D>A* pa2 = new(__FILE__, __LINE__) A(20);

То, что ты привёл — это отладочная версия оператора new (тем не менее, выделяющего память на куче) и соответствующее ему выражение new.
Кстати, MFC коварно вводит макрос new, подменяющий выражение new T на new(__FILE__,__LINE__) T. После этого макроса, разумеется, попытки перегрузить оператор new будут безуспешными.

А placement new требует вот такой оператор:
void* ::operator new(void* p, size_t /*который игнорируем*/) { /*здесь ничего не делаем*/ return p; }

Эта сигнатура зарезервирована Стандартом и в дополнительной перегрузке не нуждается — только #include <new>.
Перекуём баги на фичи!
Re: Вызов конструктора копирования для участка памяти.
От: c-smile Канада http://terrainformatica.com
Дата: 10.05.05 00:18
Оценка: 1 (1)
Здравствуйте, Denich, Вы писали:

D>Есть участок памяти, есть экземпяр объекта.

D>Каким образом можно сконструировать объект — копию заданного объекта
D>в заданном участке памяти (через конструктор копирования)?

Примерно так


 void *p = ...;

 myclass * myclass_dst_object_p = new(p) myclass( myclass_src_object );
Вызов конструктора копирования для участка памяти.
От: Denich Филиппины  
Дата: 09.05.05 23:24
Оценка:
Привет!

Есть участок памяти, есть экземпяр объекта.
Каким образом можно сконструировать объект — копию заданного объекта
в заданном участке памяти (через конструктор копирования)?

Спасибо...

Денис
Re: Вызов конструктора копирования для участка памяти.
От: sadomovalex Россия http://sadomovalex.blogspot.com
Дата: 10.05.05 07:14
Оценка:
Здравствуйте, Denich, Вы писали:

D>Привет!


D>Есть участок памяти, есть экземпяр объекта.

D>Каким образом можно сконструировать объект — копию заданного объекта
D>в заданном участке памяти (через конструктор копирования)?

D>Спасибо...

D>Денис

MSDN, ключевое слово placement new
"Что не завершено, не сделано вовсе" Гаусс
Re[3]: Вызов конструктора копирования для участка памяти.
От: Bell Россия  
Дата: 10.05.05 07:24
Оценка:
Здравствуйте, Denich, Вы писали:


D>Спасибо! Действительно именно так. Только с маленькой оговоркой -

D>оператор new должен быть перегруженным.
Нет. Это стандартная форма new (placement form).
Любите книгу — источник знаний (с) М.Горький
Re[3]: Вызов конструктора копирования для участка памяти.
От: MaximE Великобритания  
Дата: 10.05.05 08:48
Оценка:
Denich wrote:

[]

> Спасибо! Действительно именно так. Только с маленькой оговоркой -

> оператор new должен быть перегруженным.

Включи стандартный хедер <new>.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[3]: Вызов конструктора копирования для участка памяти.
От: MaximE Великобритания  
Дата: 10.05.05 08:52
Оценка:
Denich wrote:

> Здравствуйте, c-smile, Вы писали:

>
>

> D>>Есть участок памяти, есть экземпяр объекта.
> D>>Каким образом можно сконструировать объект — копию заданного объекта
> D>>в заданном участке памяти (через конструктор копирования)?
> CS>Примерно так
>

> CS> void *p = ...;
> CS> myclass * myclass_dst_object_p = new(p) myclass( myclass_src_object );
>

>
> Спасибо! Действительно именно так. Только с маленькой оговоркой -
> оператор new должен быть перегруженным.

Эту форму оператора new стандарт явно запрещает перегружать.

[lib.new.delete.placement]
18.4.1.3 Placement forms
1 These functions are reserved, a C++ program may not define functions that displace the versions in the Standard C++ library (17.4.3).


--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[3]: Вызов конструктора копирования для участка памяти.
От: Denich Филиппины  
Дата: 10.05.05 18:37
Оценка:
Здравствуйте,

Подведу предварительный итог.

По поводу передачи аргументов в функцию оператора new
в MSDN говориться следующее:

new-expression: 
[::] new [placement] new-type-name [new-initializer]
[::] new [placement] ( type-name ) [new-initializer] 

И далее

placement 
    Provides a way of passing additional arguments 
    if you overload new.
    (Создает возможность передачи дополнительных аргументов
     в случае если вы перегружаете оператор new)


Примерно то же самое говорится и в ISO стандарте от 98 года.

И нигде ни слова нет про то что new(void *ptr) обозначает
конструирование без распределения памяти.

Хотя у Страуструпа подобное описание есть с пометкой что
для использования данной конструкции надо включать файл
<new>, являющийся, кстати говоря, частью Стандартной
библиотеки.

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

Хоршо. С этим я разобрался. Спасибо за помощ. НО!
После создания объекта его еще нужно уничтожить.
Как пишет Страуструп основной способ уничтожения подобного
объекта это явный вызов деструктора.
В принципе все просто вызываем Obj->~MyClass(); и все.
Но вот когда речь доходит до шаблонов тут начинаются
проблемы.

Допустим объявление класса содержит template<class T>
и распределяемый объект имеет обобщенный тип "Т". Тогда
конструктор вызываем так — new(ptr) T;

Как вызвать деструктор для подобного объекта?

ptr->~T(); не проходит и по идее не должно.

В файле <new> есть перегруженный delete для этого случая,
но как я ни пытался вызвать его не смог, при любой записи
вызывался delete по умолчанию который пытается освободить
память, что в последствии приводит к исключению...

Денис Р.
Re[4]: Вызов конструктора копирования для участка памяти.
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 11.05.05 09:03
Оценка:
Здравствуйте, Denich, Вы писали:

D>Возможно у меня старая документация, хотя по правде говоря,

D>думается мне, что причина умолчания здесь в том что стандарт
D>Си++ не подразумевает наличие Стандартной библиотеки .

Как это не подразумевает? Смотри начиная с главы 18 Language support library и почти до конца стандарта.

D>Допустим объявление класса содержит template<class T>

D>и распределяемый объект имеет обобщенный тип "Т". Тогда
D>конструктор вызываем так — new(ptr) T;

D>Как вызвать деструктор для подобного объекта?


D>ptr->~T(); не проходит и по идее не должно.


#include <new>
#include <boost/aligned_storage.hpp>

struct T {}; // это самый обобщенный тип на свете :)

int main()
{
    boost::aligned_storage<sizeof(T)> buf;
    void* ptr = buf.address();
    T* p = new(ptr) T;
    p->~T();
}


Обрати внимание на разницу между p и ptr.

D>В файле <new> есть перегруженный delete для этого случая,

D>но как я ни пытался вызвать его не смог, при любой записи
D>вызывался delete по умолчанию который пытается освободить
D>память, что в последствии приводит к исключению...
Максим тебе это уже объяснил.
Re[4]: Вызов конструктора копирования для участка памяти.
От: Lorenzo_LAMAS  
Дата: 11.05.05 09:55
Оценка:
Не объяснишь, почему смайлик Андрею поставил? Не согласен? Или что-то другое?
Of course, the code must be complete enough to compile and link.
Re[5]: Вызов конструктора копирования для участка памяти.
От: Bell Россия  
Дата: 11.05.05 11:41
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Не объяснишь, почему смайлик Андрею поставил? Не согласен? Или что-то другое?


Мне показалась забавной форма ответа, но после твоего вопроса...
Любите книгу — источник знаний (с) М.Горький
Re[6]: Вызов конструктора копирования для участка памяти.
От: Lorenzo_LAMAS  
Дата: 11.05.05 12:20
Оценка:
B>Мне показалась забавной форма ответа, но после твоего вопроса...
B>

Совсем меня запутал
Of course, the code must be complete enough to compile and link.
Re[7]: Вызов конструктора копирования для участка памяти.
От: Bell Россия  
Дата: 11.05.05 15:26
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Совсем меня запутал

Ладно, расставим все точки над умляутами
Ответ АТ я понял так, что ничего перегружать не надо (да и нельзя), т.к. требуемая форма оператора new определена в стандартной библиотеке. С этим я вполне согласен. Формулировка же ответа вызвала у меня улыбку, поэтому я и поставил смайлик Андрею(ИМХО совершенно безобидный ). Почему это меня так повеселило — вопрос десятый, и, думаю, широкой общественности совершенно неинтересный.

ЗЫ
Впредь буду ставить смайлики только в форуме "юмор"
Любите книгу — источник знаний (с) М.Горький
Re[5]: Вызов конструктора копирования для участка памяти.
От: Denich Филиппины  
Дата: 12.05.05 02:47
Оценка:
Здравствуйте, alnsn, Вы писали:

D>>ptr->~T(); не проходит и по идее не должно.

A>#include <new>
A>#include <boost/aligned_storage.hpp>

A>struct T {}; // это самый обобщенный тип на свете :)

A>int main()
A>{
A>    boost::aligned_storage<sizeof(T)> buf;
A>    void* ptr = buf.address();
A>    T* p = new(ptr) T;
A>    p->~T();
A>}


A>Обрати внимание на разницу между p и ptr.


Я имел в виду шаблон template<class T> class ClassX
внитри которого должен вызываться p->~T();
Хотя так или иначе вы правы. Данное выражение не
вызывает ошибок, компилируется и работает нормально...
Незнаю в чем была проблема, намучился я с этим порядочно,
как не пытался делать все неправильно, а что по идее
должно было работать вызывало "Internal compiler error" и
кучу мата....

Да, вспомнил, ошибка которая выдавалась была, толи —
~T is not a member of ClassX
толи что то в этом роде...

Денис
Re[5]: Вызов конструктора копирования для участка памяти.
От: Denich Филиппины  
Дата: 12.05.05 05:05
Оценка:
Здравствуйте, MaximE, Вы писали:

>> По поводу передачи аргументов в функцию оператора new

>> в MSDN говориться следующее:

ME>Мой друг, в MSDN столько херни про С++ понаписано...


Как говорится доверяй но проверяй! А можно ли вообще создать
документацию подобного размера и там не наляпать?

>> Примерно то же самое говорится и в ISO стандарте от 98 года.

ME>Стандарт явно запрещает перегружать placement new с сигнатурами void* operator new(std::size_t size, void* ptr) throw(); void* operator new[](std::size_t size, void* ptr) throw();, и соответствующие им формы delete. [skip]

ME>Cтандарт про placement new

ME>

ME>18.4.1.3 Placement forms [lib.new.delete.placement]
ME>1 These functions are reserved, a C++ program may not define functions that displace the versions in the
ME>Standard C++ library (17.4.3).
ME>void* operator new(std::size_t size, void* ptr) throw();
ME>2 Returns: ptr.
ME>3 Notes: Intentionally performs no other action.


ME>Здесь obvious unsaid consequences — это то, что ключевое слово new вызывает соответствующую форму operator new (ключевое слово new и operator new — разные вещи) и затем вызывает конструктор объекта. Остается догадаться, что если operator new "Returns: ptr" и "Intentionally performs no other action", то остается только вызов конструктора.


Согласись, у начинающего программиста и у "борадатого" юниксойда
разные представления об "очевидных следствиях"(obvious consequences)
Стандарт, в моем понимании, — документация, а не шифр который читать
надо между строк и понимаю я его как там написано. Если написано
что функция оператора ничего кроме возврата указателя не делает, то
я это так и понимаю.

Видимо тут как и про MSDN можно сказать что в стандарте С++
"столько херни про С++ понаписано"...


Денис
Re[6]: Вызов конструктора копирования для участка памяти.
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 12.05.05 06:26
Оценка:
Здравствуйте, Denich, Вы писали:

D>Я имел в виду шаблон template<class T> class ClassX

D>внитри которого должен вызываться p->~T();

С шаблоном тоже работает:
#include <new>
#include <boost/aligned_storage.hpp>

template<class T>
void foo()
{
    boost::aligned_storage<sizeof(T)> buf;
    void* ptr = buf.address();
    T* p = new(ptr) T;
    p->~T(); // TODO: RAII прикрутить?
}

struct X {};

int main()
{
    foo<X>();
}
Re[6]: Вызов конструктора копирования для участка памяти.
От: MaximE Великобритания  
Дата: 12.05.05 07:11
Оценка:
Denich wrote:

[]

> ME>Cтандарт про placement new

> ME>

> ME>18.4.1.3 Placement forms [lib.new.delete.placement]
> ME>1 These functions are reserved, a C++ program may not define functions that displace the versions in the
> ME>Standard C++ library (17.4.3).
> ME>void* operator new(std::size_t size, void* ptr) throw();
> ME>2 Returns: ptr.
> ME>3 Notes: Intentionally performs no other action.
> ME>

>
> ME>Здесь obvious unsaid consequences — это то, что ключевое слово new вызывает соответствующую форму operator new (ключевое слово new и operator new — разные вещи) и затем вызывает конструктор объекта. Остается догадаться, что если operator new "Returns: ptr" и "Intentionally performs no other action", то остается только вызов конструктора.
>
> Согласись, у начинающего программиста и у "борадатого" юниксойда
> разные представления об "очевидных следствиях"(obvious consequences)
> Стандарт, в моем понимании, — документация, а не шифр который читать
> надо между строк и понимаю я его как там написано. Если написано
> что функция оператора ничего кроме возврата указателя не делает, то
> я это так и понимаю.

Ты правильно это понимаешь.

Напомню лишь еще раз, что operator new() — это всего лишь allocation function, эквивалентная malloc (§3.7.3). new-expression — это конструкция языка, которая находит и вызывает allocation function, а затем конструктор объекта (§5.3.4). Когда ты постигнешь, что это разные вещи, ты будешь просветлен.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.