Чтобы выполнить пользовательское отслеживание памяти (предотвращение утечек, обнаружение повреждений), мне нужно использовать новое размещение для создания объектов C ++, что прекрасно работает, но я изо всех сил пытаюсь выяснить, как передать аргументы конструктору, так как он вызывается из макроса (поэтому файл + строка может быть предоставлен автоматически).
Функция:
template <typename T>
T*
cpp_new(
const char *file,
size_t line
)
{
T *n = (T*)tracked_allocate(&memory_context, sizeof(T), file, line);
if ( n )
{
construct(n);
}
else
{
throw std::bad_alloc();
}
return n;
}
Это вызывается через макрос:
#define new_object(type) cpp_new<type>(__FILE__, __LINE__)
Размещено новое:
template <typename T>
void
construct(
T *obj
)
{
obj = new (obj) T;
}
Макросы va_list будут охватывать расширение для переменного числа аргументов, только я не хочу указывать количество аргументов, которое имеет конструктор, удаляя va_arg (), и не могу использовать va_start (), так как он ожидает формат.
Это прошло немного над моей головой: http://www.drdobbs.com/cpp/calling-constructors-with-placement-new/232901023?pgno=2
Есть ли способ, которым я могу использовать __VA_ARGS__
из new_object и передать их в функцию построения? У каждого объекта есть только один конструктор, но есть много разных типов объектов, принимающих разные параметры, поэтому я хочу удалить как можно больше ручного обслуживания.
Или есть просто лучший способ сделать то, что я пытаюсь сделать?
Вы не должны иметь дело с конструктом-если-выделение-успешно. Это работа new
-expression. Он делает это правильно, как операция, подобная транзакции: либо все успешно выполнено, либо выполняется очистка перед распространением исключения.
Итак, избавившись от этой ответственности, работа вашего макроса заключается в том, чтобы делать то, что могут делать только макросы, а именно подбирать имя файла и строку.
Эти элементы могут / должны быть переданы в функцию распределителя, которая технически является «новым местом размещения», хотя здесь она будет не построить на месте: это размещение нового просто потому, что у него есть дополнительные пользовательские аргументы, например:
bool hopefully( bool const c ) { return c; }
template< class X >
bool throw_( X const& x ) { throw x; }
void* operator new( size_t const size, char const* const filename, int const linenum )
{
void* const p = tracked_allocate( &memory_context, size, filename, linenum );
hopefully( p != 0 )
|| throw_( std::bad_alloc() )
return p;
}
Вам нужно определить соответствующую функцию освобождения места размещения, или же new
выражение не сможет освободиться, когда конструктор сгенерирует:
void operator delete( void* const p )
{
// Your custom deallocation.
}
void operator delete( void* const p, char const*, int )
{
::operator delete( p );
}
Теперь вашему макросу просто нужно предоставить соответствующие аргументы размещения, например:
#define SOURCE_LINE_INFO __FILE__, __LINE__
Тогда вы можете просто сказать, как,
new (SOURCE_LINE_INFO) MyType( arg1, arg2, arg3 )
Для более многоразового решения рассмотрите определение struct
держать имя файла и номер строки. Затем макрос сводится к созданию экземпляра этого типа и может использоваться более широко. В частности, его можно использовать для регистрации звонков.
Других решений пока нет …