Posted inInformation Technology

C++ 11 and Qt — Part 4 Test Your Compiler

As promised, here is a test to see if your compiler actually handles initialization lists correctly or adopted a “last one in wins” strategy.

#ifndef SMALLDATA_H
#define SMALLDATA_H

class SmallData
{
public:
    explicit SmallData( int nuVal);
    explicit SmallData();
    ~SmallData();
    
private:
    int m_data = 8;

};

#endif // SMALLDATA_H

 

#include "SmallData.h"
#include <iostream>

SmallData::SmallData()
{
    std::cout << "SmallData Default constructor data value " << m_data << std::endl;
}

SmallData::SmallData(int nuVal) :
    m_data(nuVal)
{
    std::cout << "SmallData nuVal constructor data value " << m_data << std::endl;
}

SmallData::~SmallData()
{
}

#ifndef OUTERCLASS_H
#define OUTERCLASS_H

#include "SmallData.h"

class OuterClass
{
public:
    explicit OuterClass();
    ~OuterClass();
    
private:
    SmallData m_1;
    SmallData *m_ptr=nullptr;
    SmallData m_2{33};

};

#endif // OUTERCLASS_H

 

#include "OuterClass.h"

OuterClass::OuterClass()
{
    m_ptr = new SmallData(12);
}

OuterClass::~OuterClass()
{
    if (m_ptr != nullptr)
        delete m_ptr;
}

 

#include <iostream>
#include "OuterClass.h"

int main(int argc, char **argv)
{
    std::cout << "About to create create variable o" << std::endl;
    OuterClass o;
    
    std::cout << "About to new ptr" << std::endl;
    OuterClass *ptr = new OuterClass();
    std::cout << "Finished new now deleting" << std::endl;
    delete ptr;
    ptr = nullptr;
    
}

 

Compiling and executing this code yields the following output.

About to create create variable o
SmallData Default constructor data value 8
SmallData nuVal constructor data value 33
SmallData nuVal constructor data value 12
About to new ptr
SmallData Default constructor data value 8
SmallData nuVal constructor data value 33
SmallData nuVal constructor data value 12
Finished new now deleting
Press ENTER to continue...

Careful readers will note that I made use of another C++ 11 feature nullptr. This was added to the language to get around all of the issues with 0 being used for everything. Basically one of the main problems/hacks from old C days:

char *ptr = 0;
int x = 0;
...
x = ptr;

Oh come on! You’ve all seen code which did that, especially if you started back when the Zortech C++ compiler reigned supreme on DOS, before Watcom kicked its butt at the same time Symantec ran it into the ground. If you came from 8086 assembly you had a much higher probability of using pointers and integers interchangeably. Even if you didn’t come from assembly language programming, some hardware which operated via configurable shared memory used to have you load the base address of the shared memory range as an integer into the card/device/driver. Code like that is prevalent on every desktop, laptop and tablet today. What do you think those BIOS settings do which allow you to configure the amount of RAM to share with the video card?

The problem isn’t so much storing a pointer in an integer. The real problem is when something like this happens:

char *ptr = 0;
int x = 2;
...
ptr = x;

Maybe, just maybe you lead the world’s most charmed life. Maybe, just maybe the very next instruction attempts to dereference the pointer. Most people don’t get that lucky. Usually it is not until many hundreds of lines later when you actually use the pointer, perhaps in a different method, when you get your access violation/segmentation fault/whatever your OS of choice chooses to slam you with when accessing out of process protected memory. Of course, this assume you aren’t in an embedded target running as root where the OS says “Sure! You can overwrite a chunk of me!”

At any rate, the output from this test says my fears of a “last one in wins” shortcut were unfounded for this compiler. You really should run the test with your compiler though.