У меня есть следующая структура в C ++:
struct wrapper
{
// Param constructor
wrapper(unsigned int _id, const char* _string1, unsigned int _year,
unsigned int _value, unsigned int _usage, const char* _string2)
:
id(_id), year(_year), value(_value), usage(_usage)
{
int len = strlen(_string1);
string1 = new char[len + 1]();
strncpy(string1, _string1, len);
len = strlen(_string2);
string2 = new char[len + 1]();
strncpy(string2, _string2, len);
};
// Destructor
~wrapper()
{
if(string1 != NULL)
delete [] string1;
if(string2 != NULL)
delete [] string2;
}
// Elements
unsigned int id;
unsigned int year;
unsigned int value;
unsigned int usage;
char* string1;
char* string2;
};
Допустим, в main.cpp я выделил память для одного объекта этой структуры:
wrapper* testObj = new wrapper(125600, "Hello", 2013, 300, 0, "bye bye");
Могу ли я теперь удалить весь объект, используя арифметику указателей и указатель, который указывает на один из элементов структуры?
Что-то вроде этого :
void* ptr = &(testObj->string2);
ptr -= 0x14;
delete (wrapper*)ptr;
Я проверил себя и, видимо, это работает, но я не уверен на 100%, что эквивалентно delete testObj
,
Благодарю.
Могу ли я теперь удалить весь объект, используя арифметику указателей и указатель, который указывает на один из элементов структуры?
Теоретически да.
Указатель, который вы даете delete
должно иметь правильное значение, и на самом деле не имеет значения, получено ли это значение из существующей переменной-указателя или путем «подстройки» таким образом.
Вы также должны учитывать тип указателя; если ничего другого, вы должны бросить char*
перед выполнением арифметики, чтобы вы двигались с шагом в один байт. Ваш текущий код не будет компилироваться, потому что ISO C++ forbids incrementing a pointer of type 'void*'
(насколько большой void
?).
тем не мение, рекомендую не делаю это вообще. Ваш магический номер 0x14
является ненадежным, учитывая выравнивание и заполнение и потенциал вашей структуры, чтобы изменить форму.
Вместо этого сохраните указатель на фактический объект. Также остановитесь со всем ужасным беспорядком памяти, и используйте std::string
, В настоящее время отсутствие конструктора копирования представляет собой неприятную ошибку.
Технически такой код работал бы (игнорируя тот факт, что wrapper testObj
должно быть wrapper* testObj
и что смещение не обязательно 0x14
например, сборки отладки иногда дополняют структуры, и, возможно, некоторые другие детали, которые я пропустил), но это ужасная, ужасная идея. Я не могу подчеркнуть, насколько это ужасно.
Вместо 0x14
вы могли бы использовать offsetof
макро.
Если вам нравится проводить ночи в компании отладчика, не стесняйтесь делать это.
Я предполагаю, что причиной вопроса является явное любопытство о том, возможно ли использовать арифметику указателей для перехода от членов к родителю, а не то, что вы действительно хотели бы сделать это в рабочем коде. Пожалуйста, скажи мне, что я прав.
Вы Можно делать подобные вещи с арифметикой указателей. Ли ты должен это совершенно другая история. Рассмотрим этот макрос (я знаю … я знаю …), который даст вам базовый адрес структуры с учетом ее типа, имя члена структуры и указатель на этот член:
#define ADDRESS_FROM_MEMBER(T, member, ptr) reinterpret_cast<T*>( \
reinterpret_cast<unsigned char *>(ptr) - (ptrdiff_t)(&(reinterpret_cast<T*>(0))->member))