Есть участок памяти, есть экземпяр объекта.
Каким образом можно сконструировать объект — копию заданного объекта
в заданном участке памяти (через конструктор копирования)?
Спасибо...
Денис
Re: Вызов конструктора копирования для участка памяти.
Здравствуйте, Denich, Вы писали:
D>Есть участок памяти, есть экземпяр объекта. D>Каким образом можно сконструировать объект — копию заданного объекта D>в заданном участке памяти (через конструктор копирования)?
D>>Есть участок памяти, есть экземпяр объекта.
D>>Каким образом можно сконструировать объект — копию заданного объекта
D>>в заданном участке памяти (через конструктор копирования)?
CS>Примерно так
Здравствуйте, Denich, Вы писали:
D>Здравствуйте, c-smile, Вы писали:
D>
D>>>Есть участок памяти, есть экземпяр объекта.
D>>>Каким образом можно сконструировать объект — копию заданного объекта
D>>>в заданном участке памяти (через конструктор копирования)?
CS>>Примерно так
D>
Здравствуйте, Denich, Вы писали:
D>Привет!
D>Есть участок памяти, есть экземпяр объекта. D>Каким образом можно сконструировать объект — копию заданного объекта D>в заданном участке памяти (через конструктор копирования)?
D>Спасибо... D>Денис
MSDN, ключевое слово placement new
"Что не завершено, не сделано вовсе" Гаусс
Re[3]: Вызов конструктора копирования для участка памяти.
D>Спасибо! Действительно именно так. Только с маленькой оговоркой - D>оператор new должен быть перегруженным.
Нет. Это стандартная форма new (placement form).
Любите книгу — источник знаний (с) М.Горький
Re[3]: Вызов конструктора копирования для участка памяти.
Denich wrote:
> Здравствуйте, c-smile, Вы писали: > >
> D>>Есть участок памяти, есть экземпяр объекта.
> D>>Каким образом можно сконструировать объект — копию заданного объекта
> D>>в заданном участке памяти (через конструктор копирования)?
> CS>Примерно так
>
> > Спасибо! Действительно именно так. Только с маленькой оговоркой - > оператор 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, Вы писали:
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[3]: Вызов конструктора копирования для участка памяти.
По поводу передачи аргументов в функцию оператора 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]: Вызов конструктора копирования для участка памяти.
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
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[4]: Вызов конструктора копирования для участка памяти.
Здравствуйте, 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, Вы писали:
L_L>Совсем меня запутал
Ладно, расставим все точки над умляутами
Ответ АТ я понял так, что ничего перегружать не надо (да и нельзя), т.к. требуемая форма оператора new определена в стандартной библиотеке. С этим я вполне согласен. Формулировка же ответа вызвала у меня улыбку, поэтому я и поставил смайлик Андрею(ИМХО совершенно безобидный ). Почему это меня так повеселило — вопрос десятый, и, думаю, широкой общественности совершенно неинтересный.
ЗЫ
Впредь буду ставить смайлики только в форуме "юмор"
Любите книгу — источник знаний (с) М.Горький
Re[5]: Вызов конструктора копирования для участка памяти.
Здравствуйте, 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]: Вызов конструктора копирования для участка памяти.
Здравствуйте, 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]: Вызов конструктора копирования для участка памяти.
> 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). Когда ты постигнешь, что это разные вещи, ты будешь просветлен.