Выделено отдельной темой.
В том же разделе, в плюсах я сам начинающий :-), если что - меня поправят.
Цитата(AHTOXA @ Nov 6 2009, 22:47)

А что это? А то может мне тоже это нравится, а я и не знаю

----
Почитал. Пока не понял, нравится ли... Но скорее да, чем нет

Это такой стандартный способ сделать то, что делать нехорошо. Ну как goto - нехорошо, а break/continue/switch+case - хорошо (правда, на switch+case делается такой Duff's device, что вся структурность в гробу переворачивается, но зато без goto).
Конкретнее, placement new - это способ сделать
Код
#include "foo.h"
unsigned char buf[sizeof(foo)]; // выделяем место под экземпляр
foo *pfoo = reinterpret_cast<foo*>(buf); // заводим указатель#define
pfoo->foo(0x88); // ( . ) конструиреум
pfoo->action(); // пользуемся
pfoo->~foo(); // удаляем
Тут сделать можно всё, кроме строки, помеченной ( . ) - ну нельзя так.
Зато можно так
Код
#include "foo.h"
unsigned char buf[sizeof(foo)]; // выделяем место под экземпляр
foo *pfoo = new(buf) foo(0x88); // конструиреум и приводим указатель
pfoo->action(); // пользуемся
pfoo->~foo(); // удаляем
и эта штука и называется placement new. Она не проверяет, достаточно ли места в предоставленном буфере и возвращает указатель на начало буфера, приведенный к конструируемому типу. Короче, сплошное "фу". Но такая лапочка.
Как было написано в какой-то статье по этому делу, "если вы не знаете, что такое alignment, то и placement new лучше не пользуйтесь".
Фактически это глобальная перегрузка оператора new своим аллокатором, тип "аллокатора" void* и он ничего не делает.
В библиотеке должна быть готовая реализация перегруженного оператора, но в avr-gcc её нет. И не надо, inline она смотрится куда лучше.
Код
#include <stdlib.h> // size_t
// placement new support - сответствующий стандарту прототип
inline void* operator new(size_t size, void* ptr) throw()
{
(void)size;
return ptr;
}
Ну а теперь - почему мне это нравится.
Пусть у нас есть несколько классов, которые используются строго по очереди.
Если экзмепляры заводить статически - абсолютно зря жрётся место в ОЗУ.
Если динамически - надо прицепть new/delete (пусть хоть и отмапленные на malloc/free) - а это лишний код и возможные проблемы с фрагментацией памяти (хотя если new/delete в программе всё равно нужны, то почему бы и нет).
Но можно так (NOINLINE для удобства разбора функции kwa() ):
Код
class foo {
public:
NOINLINE foo(uint8_t mask) : _mask(mask) { PORTB &= ~_mask; DDRB |= _mask; }
NOINLINE ~foo() { PORTB |= _mask; DDRB &= ~_mask; }
NOINLINE void action() { PORTB ^= _mask; }
private:
uint8_t _mask;
};
class moo {
public:
NOINLINE moo(uint8_t mask, uint8_t period)
: _mask(mask), _period(period), _cnt(period)
{ PORTB &= ~_mask; DDRC |= _mask; }
NOINLINE ~moo() { DDRC &= ~_mask; }
NOINLINE void action() {
if( --_cnt == 0) {
_cnt = _period;
PORTC ^= _mask;
}
}
private:
uint8_t _mask;
uint8_t _period;
uint8_t _cnt;
};
const int bufsize = sizeof(foo) > sizeof(moo) ? sizeof(foo) : sizeof(moo);
uint8_t buf[bufsize];
void kwa()
{
uint8_t i;
foo *pfoo = new(buf) foo(0x11);
i = 8;
do { pfoo->action(); } while(--i);
pfoo->~foo();
moo *pmoo = new(buf) moo(0x11,3);
i = 8;
do { pmoo->action(); } while(--i);
pmoo->~moo();
}
Код kwa()
Код
.global _Z3kwav
.type _Z3kwav, @function
_Z3kwav:
push r17
; operator new(size_t,void*) заинлайнился в ничто
ldi r24,lo8(buf)
ldi r25,hi8(buf)
ldi r22,lo8(17)
rcall _ZN3fooC1Eh; конструктор foo
ldi r17,lo8(8)
.L20:
ldi r24,lo8(buf)
ldi r25,hi8(buf)
rcall _ZN3foo6actionEv; попользовались
subi r17,lo8(-(-1))
brne .L20
ldi r24,lo8(buf)
ldi r25,hi8(buf)
rcall _ZN3fooD1Ev; деструктор foo
; new опять пропал
ldi r24,lo8(buf)
ldi r25,hi8(buf)
ldi r22,lo8(17)
ldi r20,lo8(3)
rcall _ZN3mooC1Ehh; конструктор moo
ldi r17,lo8(8)
.L21:
ldi r24,lo8(buf)
ldi r25,hi8(buf)
rcall _ZN3moo6actionEv; попользовались
subi r17,lo8(-(-1))
brne .L21
ldi r24,lo8(buf)
ldi r25,hi8(buf)
rcall _ZN3mooD1Ev; деструктор moo
pop r17
ret
Массив для экземпляров классов можно и на стеке завести, что лучше - зависит от условий. Даже alloca() может быть лучше malloc/free
К сожалению, нельзя сказать delete(buf) pfoo - компилятор путается, нужно вручную звать деструктор (ну а удалять ничего и не нужно)
Если деструкторы по задаче классу не нужны, лучше не вызывать и не заводить даже пустые.
Ну так пока всё.