Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this work? [C++; void pointer]

I thought I did something stupid - at least I thought it was. My question is: why does this work?

template<typename T>
class yarray
{
public:
    yarray() {
        pContainer = new T[1]; //initialize as array with size 1
        unCount = 0U; //counter
    }
    ~yarray() {
        delete[] pContainer; //cleanup
        pContainer = nullptr;
    }

    void push_back(T data)
    {
        ((T*)pContainer)[unCount] = data; //set (shouldn't it throw an exception when unCount > 0?
        unCount++; //increment
    }

    T operator[](const unsigned int & index)
    {
        if (index <= unCount)
            return ((T*)pContainer)[index];

        return T();
    }

private:
    void * pContainer;
    unsigned int unCount;
};

int main()
{
    yarray<int> klo;

    klo.push_back(342);
    klo.push_back(5563);

    for (auto i = 0; i < 2; ++i)
        std::cout << klo[i] << std::endl;
}

The code works perfectly in C++14 (Visual Studio). Shouldn't it throw an exception after the second push_back?

Update question: What if you don't initialize pContainer with new, but with pContainer = &T() instead? Doesn't that affect somehow the memory or even endanger other programs? When I use a class that prints out when it was constructed/destructed, all objects that were created will be destroyed right after the construction. Why can I use them even after destruction?

like image 413
terrakuh Avatar asked Feb 08 '23 06:02

terrakuh


2 Answers

A program with an out of bounds array access has undefined behavior. It is not required to throw an exception.

As to why it works, it's just bad luck.

like image 187
Pete Becker Avatar answered Feb 11 '23 22:02

Pete Becker


The addressable memory of a computer is set to a number of pages. The current crop have 4k (4096 bytes). On a modern operating system, then 4k of memory is either addressable, or not addressable.

For the program to fail, then the memory would need to be

  1. buffed up to the end of a page xxxxxxxxxxxxDDDDD (x unimportant D data).
  2. Also the next page needs to be unmapped - not part of the process.

Only when these are true, does the system fault.

Programs such as valgrind (linux) and application verifier (windows) modify the memory allocation system to engineer this form of failure, but without this system, then the code would not always fault.

On simpler systems (such as arduino), then all memory is available, and this would never fault. What would happen, is that the memory would belong to something else, and cause a difficult to find fault.

like image 21
mksteve Avatar answered Feb 11 '23 23:02

mksteve