Přetěžování new a delete v C++

Přetěžování new a delete v C++
« kdy: 12. 10. 2011, 15:20:02 »
Programování zdar.

Řeším tu jednu nekonzistenci okolo přetěžování new a delete. Chtěl bych si ujistit, že jsem to pochopil dobře, a že mi nic neuniklo.
Mohu si u vlastní třídy přetížit operator new s placementem

void *operator new(size_t sz, void *a, char *c,...)

Pokud chci objekt té třídy dealokovat nějakým specifickým způsobem, musím tam mít něco takového

void operator delete(void *ptr, size_t sz)

To je výborný, protože hodnotu sz nemusím nikam ukládat. Jenže je zde ještě jedna specifická a povinná funkce

void operator delete(void *ptr, void *a, char *c,...)

která se volá v případě, že konstruktor hodí výjimku. Zkoušel jsem tam narvat size_t sz, a vypadá to, že to sebralo jen GCCčko, ale moc si s tím nejsem jist, protože jsem to netestoval. Rozhodně mi u toho MSVC hodí warning, protože nedokáže spárovat placement new s ...

void operator delete(void *ptr, size_t sz, void *a, char *c,...)

Chápu to tedy dobře tak, že si velikost alokované paměti stále musím ukládat někam vedle? A že se jedná o nekonzistenci v normě, nebo jen v MSVC?
« Poslední změna: 12. 10. 2011, 23:04:21 od Petr Krčmář »


Re: přetěžování new a delete v C++
« Odpověď #1 kdy: 12. 10. 2011, 17:38:40 »
Tak si odpovím sám, dá se to obejít pomocí pomocného objektu, který si velikost zapamatuje. Vyzkoušený příklad v MSVC i v GCC

Objekt Allocator zde představuje placeholder, pro nějaký objekt provádějící alokace kdesi a předpokládá se, že místo standardních new a delete se bude volat on s parametry velikost, potažmo pointer a velikost. Alokace je zde provedena přes new a delete. To co je třeba sledovat je jakým způsobem se zjišťuje velikost alokované paměti při delete bez nutnosti tuto informaci ukládat spolu s alokovaným blokem

Kód: [Vybrat]

#include <iostream>
#include <stdexcept>
#include <memory>


class Allocator {
public:


};

class AllocatorHelper {
public:

AllocatorHelper(Allocator &hlp):rsz(0),hlp(hlp) {
std::cout << "Allocator helper construction. " << std::endl;
}

~AllocatorHelper() {
std::cout << "Allocator helper destructor. " << std::endl;
}


void rememberSize(size_t sz) const {
rsz = sz;
std::cout << "Allocator remembering size: " << sz << std::endl;
}

size_t getSize() const {return rsz;}


protected:

mutable size_t rsz;
Allocator &hlp;
};

class TestClass {

int a;
public:
TestClass(int a):a(a) {}

virtual ~TestClass() {}

void *operator new(size_t sz, const AllocatorHelper &alc) {
std::cout << "Allocating: " << sz << std::endl;
alc.rememberSize(sz);
return ::operator new(sz);
}

void operator delete(void *ptr, const AllocatorHelper &alc) {
std::cout << "In-exception deallocating: " << alc.getSize() << std::endl;
::operator delete(ptr);
}

void operator delete(void *ptr, size_t sz) {
std::cout << "Normal deallocating: " << sz << std::endl;
::operator delete(ptr);
}
};

class TestClass2: public TestClass {
double z;

public:
TestClass2(int a, double z):TestClass(a) {throw std::runtime_error("nejde to");}


};

int main(int argc, char * argv[])
{
try {
Allocator hlp;

std::auto_ptr<TestClass> a(new(hlp) TestClass(10));
std::auto_ptr<TestClass> b(new(hlp) TestClass2(10,12.0));


return 0;
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
}

Sten

Re: přetěžování new a delete v C++
« Odpověď #2 kdy: 12. 10. 2011, 18:30:44 »
Hmm, vypadá, že toho si nikdo ani při revizi ISO C++ nějak nevšiml.

Ve standardu se totiž píše, že funkce operator delete může mít druhý parametr s velikostí, ale zároveň se u placement delete funkce píše, že má totožné argumenty jako placement new funkce s výjimkou toho prvního, který je void* místo std::size_t. Zřejmě to tedy závisí na implementaci a navíc to asi může mít fatální následky, pokud v parametru placement new použijete std::size_t.

Re: přetěžování new a delete v C++
« Odpověď #3 kdy: 12. 10. 2011, 19:56:56 »
Stene, to je dobra pripominka, vim, ze jsem nekde mel kod, kde se do new daval extra parametr urcujici o kolik vetsi ma byt alokovany prostor pro objekt, do ktereho jsem pak ukladal nejaka variabilni data. Zrovna placement delete v tomhle tvaru (se size_t) jsem tam mel. Nastesti se to uz nikde nepouziva