0

I am trying to program a CVariant class which will be used by a CArray class which has a member std::vector<CVariant> m_Array.

The header part of the CVariant class is as follows:

class CVariant {
    static double TOLERANCE;

    typedef union Element {
        std::string m_String;
        double m_Number;
        Element() {
            memset(this, 0, sizeof(Element));
        }
        Element(std::string str) {
            new(&m_String)std::string(str);
        }
        Element(double num) {
            //m_String.~basic_string();
            new(&m_Number)double(num);
        }
        ~Element() {
            m_String.~basic_string();
        }
    }Element;

public:
    typedef enum TYPE { STRING, NUMBER } TYPE;

    CVariant() {  }
    CVariant(const std::string str);
    CVariant(const double num);
    CVariant(const CVariant& rhs);
    CVariant& operator=(const CVariant& rhs);

The cpp is:

CVariant::CVariant(const std::string str)
{
    m_Element = new Element(str);
    m_Type = STRING;
}

CVariant::CVariant(const double num)
{
    m_Element = new Element(num);
    m_Type = NUMBER;
}

CVariant::CVariant(const CVariant& rhs)
{
    m_Element->m_String = rhs.GetString();
    m_Element->m_Number = rhs.GetNumber();
    m_Type = rhs.GetElementType();
}

CVariant& CVariant::operator=(const CVariant& rhs)
{
    if (this == &rhs) return *this;

    m_Element->m_String = rhs.GetString();
    m_Element->m_Number = rhs.GetNumber();
    m_Type = rhs.GetElementType();

    return *this;
}

The following part of the code crashes :

CVariant variant(number);
m_Array.at(i)=variant;

If I run the code without making it union, it works well; however, with union it crashes. I tried different combinations, such as anonymous unions but still could not get it to work properly.

EDIT 1: Upon the comment, the following changes fixes the problem:

CVariant::CVariant(const CVariant& rhs)
{
    m_Type = rhs.GetElementType();
    if(m_Type==STRING)  m_Element = new Element (rhs.GetString());
    if(m_Type==NUMBER) m_Element = new Element(rhs.GetNumber());
}

CVariant& CVariant::operator=(const CVariant& rhs)
{
    if (this == &rhs) return *this;

    m_Type = rhs.GetElementType();
    if (m_Type == STRING)   m_Element = new Element (rhs.GetString());
    if (m_Type == NUMBER) m_Element = new Element(rhs.GetNumber());

    return *this;
}
macroland
  • 973
  • 9
  • 27
  • Possible duplicate of [Accessing inactive union member and undefined behavior?](https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior) – 1201ProgramAlarm Mar 03 '18 at 02:37
  • 2
    In your copy constructor and assignment operator, you are accessing both members of the union, when you can safely only access the last one that was set (the `double`, in your example). Since the `string` field has garbage in it when you try to copy the value, you get the crash. – 1201ProgramAlarm Mar 03 '18 at 02:38
  • Thanks, it worked! – macroland Mar 03 '18 at 02:57

0 Answers0