1

Я использую виртуальное наследование с выбором классов в C++. В настоящее время он разрушается при уничтожении. Кажется, он компилируется в онлайн-компиляторах, однако, когда я запускаю Visual Studio, он сбой.Размещение нового сбоя при использовании с виртуальной иерархией наследования в Visual C++

У меня есть чистый виртуальный базовый класс, который унаследован практически благодаря его реализации. Затем у меня есть третий класс, который наследуется от реализации регулярно. Я использую внутреннюю систему для создания и освобождения памяти. Под капотом используется новое место размещения с выровненным malloc. Затем он освобождает память. Я создал этот минимальный пример. Это не совсем то, что я делаю, но похоже, что у меня подобная проблема.

#include <iostream> 
#include <string> 

int main() 
{ 
    class Animal { 
     public: 
     Animal() { } 
     virtual ~Animal() { } 
     virtual void eat() { } 

    }; 

    class Mammal : public virtual Animal { 
     public: 
     virtual void breathe() { } 

    }; 

    class WingedAnimal : public virtual Animal { 
     public: 
     virtual void flap() { } 
    }; 

    // A bat is a winged mammal 
    class Bat : public Mammal, public WingedAnimal { 

    }; 

    Animal* bat = new(malloc(sizeof(Bat))) Bat; 
    bat->~Animal(); 
    free(bat); 
    printf("Done!"); 
} 

Как я уже сказал, этот пример напечатает «Готово» в онлайн-компиляторе. Однако в Visual Studio 2015 он, похоже, падает без объекта bat. Я довольно новичок в виртуальном наследовании и размещении нового. Кто-нибудь видит проблему?

+0

@Barry http://cpp.sh/2vd4t предоставляет именно то, что ... вставляем визуальную студию, и у вас есть проблема. Вот он-лайн, который вы можете использовать: http://webcompiler.cloudapp.net/. Насколько я вижу этот ответ почти на всех моих вопросах. Возможно, вы могли бы указать на то, чего не хватает, чтобы я мог улучшить в будущем? – marsh

+2

Проводка ссылок на код не рекомендуется. Почтовый код в самом вопросе. –

+3

@jeff Он использует синтаксис размещения, поэтому malloc просто выделяет необработанную память; new инициализирует его как объект C++. Затем он явно называет деструктора и звонит бесплатно. Это законно. И производные классы всегда имеют виртуальный деструктор, когда они наследуют класс, который имеет один. –

ответ

3

malloc возвращает свежий адрес памяти, operator new помещает Bat по этому адресу, а также преобразование в Animal*подстраивается и адрес. Теперь переменная bat находится где-то внутри блока malloc. free IN невозможно.

Bat* bat0 = new(malloc(sizeof(Bat))) Bat; 
Animal* bat = bat0; 
std::cout << bat0 << " " << bat << "\n"; 

gcc печатает два одинаковых адреса, в то время как VC++ печатает два разных. Любое поведение совершенно нормально и допускается стандартом, даже если не задействовано множественное наследование. Большинство компиляторов фактически не корректируют адрес с единственным наследованием, но есть некоторые исключения.

Чтобы быть в безопасности, не полагайтесь на два одинаковых адреса.

можно восстановить исходный адрес по динамической отливке void*:

free(dynamic_cast<void*>(bat)); 

должен быть в порядке. Разумеется, виртуальная функция требуется для динамического приведения, как обычно.

Update: dynamic_cast<void*> восстанавливает первоначальный указатель, но free по-прежнему падает с VC++. Понятия не имею почему.

Правильный метод интеграции менеджер стороннего памяти в C++ программа перегружать operator new и operator delete

void* ::operator new(size_t sz) { return my_managed_malloc(sz); } 
void ::operator delete (void* ptr) { return my_managed_free(ptr); } 

Поместите их в любой файл, один C++ в программе (если у вас есть библиотеки DLL, то во всех DLL) и обычно использовать C++, без явно определенных указателей указателя.

Для получения дополнительной информации, http://en.cppreference.com/w/cpp/memory/new/operator_new.

+0

Большое спасибо, это имеет смысл. Я наследую базу кода, которая использует заводские функции CreateAnimal() и DestroyAnimal(). Есть ли способ заставить существующую систему работать? Животное в моем случае является чистым виртуальным классом, и каждая реализация полностью скрыта от пользователя, поэтому я не могу иметь функцию CreateBat(). Нужно ли мне внутренне держать ссылку на соответствующий указатель malloc? Правильно ли я полагаю, что приведение к правильному типу не будет работать, поскольку у меня все еще есть неправильный адрес? – marsh

+0

Почему вызов delete не возвращает значение? Как будто я использовал обычный новый звонок? – marsh

+0

@marsh см. Обновление. –

Смежные вопросы