Баг или фитча?
От: nen777w  
Дата: 05.09.19 11:07
Оценка: 11 (2)
Добрый час.
  "Есть такой код."
#include <iostream>

class Object
{
public:
    Object()
        : p(nullptr)
    {
        int n = 0;
        n++;
    }

    virtual ~Object()
    {
        if (p) {
            delete p;
        }
    }

private:
    int * p;
};

class IPrimitive : public virtual Object
{

};

class ITrailerable : public virtual Object
{

};

class IStableInfo : public virtual Object
{

};

class Primitive : public virtual IPrimitive, public virtual ITrailerable
{
private:
    int arr[100];
};

class IObject : public virtual Object
{

};

class ISerializable : public virtual Object
{

};

class IntermObject : public Primitive, public virtual IObject, public virtual ISerializable, public IStableInfo
{
public:
    IntermObject()
    {
    }

    IntermObject(int v)
        : IntermObject()
    {
        throw "uups";
    }

    IntermObject(int v, int t)
        : IntermObject(v)
    {
        
    }

    ~IntermObject()
    {
        int n = 0;
        n++;
    }

private:
    int n;
    bool b;
};

class IPage : public virtual ITrailerable
{

};

class IPages : public virtual Object
{

};

class IPageTreeNode : public virtual IObject, public IPage, public IPages
{

};

class PageTreeNode final : public IntermObject, public IPageTreeNode
{
public:
    PageTreeNode()
        : IntermObject(10, 20)
    {}
};


int main()
{
    std::cout << "Hello !\n"; 
    
    try
    {
        new PageTreeNode();
    }
    catch (...)
    {[img][/img]
        std::cout << "Catch!\n";
        int n = 0;
        n++;
    }

    std::cout << "World!\n"; 
}


Проблема в том что при выборосе исключения:
IntermObject(int v)
        : IntermObject()
    {
        throw "uups";
    }


В деструкторе Object происходит AV (Windows — cl) или Seg.Fault (Linux — gcc)

  "Из за неправильного смещения:"


Вот такое изменение:
class PageTreeNode final : public IntermObject, public virtual IPageTreeNode


Исправляет проблему с падением, но приводит к двойному вызову деструктора ~Object() (конструктор вызывается 1 раз)
Мне не очень понятно зачем здесь виртуальное наследование, и правы ли компиляторы?

Другой пример:
struct Object
{
    Object() = default;
    virtual ~Object() = default;
};

struct IntermObject : public virtual Object
{
    IntermObject() = default;
    IntermObject(int v) : IntermObject() {}
};

struct PageTreeNode : public IntermObject
{
    PageTreeNode() : IntermObject(1) {}
};

int main()
{
    new PageTreeNode();
}


Уже не приводит к seg. fault у gcc, но приводит к AV у cl (при запуске исполняемого файла).
Замена = default на обычную имплементацию "по старинке" решает проблему с cl.

cl.exe — Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27031.1
gcc — из https://www.onlinegdb.com
Отредактировано 05.09.2019 11:16 nen777w . Предыдущая версия . Еще …
Отредактировано 05.09.2019 11:14 nen777w . Предыдущая версия .
Отредактировано 05.09.2019 11:09 nen777w . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.