1

The code I'm working on :

I had the following code (with an error about the index in main.cpp) :

Sample.hpp :

#ifndef SAMPLE_HPP
# define SAMPLE_HPP

# include <iostream>
# include <string>

class Sample{
public:
    Sample(void);
    ~Sample(void);
    void    tellname(void) const;
private:
    std::string     _name;
};

#endif

Sample.cpp :

#include <iostream>
#include "Sample.hpp"

Sample::Sample(void){
    this->_name = "testname";
    return;
};

Sample::~Sample(void){
    return;
}

void    Sample::tellname(void) const{
    std::cout << "Name : " << this->_name << std::endl;
    return;
}

main.cpp

#include "Sample.hpp"

int     main(void){
    int     i;
    Sample  *test;

    test = new Sample[4];
    i = 0;
    while (i++ < 4)          // I know : i++; shouldn't be here
        test[i].tellname();
    delete [] test;
    return 0;
}

If I compile this I get the following output :

Name : testname
Name : testname
Name : testname
Name :

My question is :

About the last line, it calls a method (void Sample::tellname(void)) but from an instance that is not in the range of the table (test[4] doesn't exist).

However, it still calls tellname() even the instance it calls it from doesn't exist. It just considers its _name field being empty.

How is this possible?

vmonteco
  • 14,136
  • 15
  • 55
  • 86

3 Answers3

5

It's simply undefined behavior, something C++ imposes no requirements on so "anything could happen". What you're seeing is just a coincidence and worthless to reason about: next time you run it could crash, display nyan cat and so on.

edmz
  • 8,220
  • 2
  • 26
  • 45
  • 1
    Also see [Undefined, unspecified and implementation-defined behavior](https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior). – edmz Jan 06 '16 at 13:14
3

i goes from 1 to 4 include, since tellname is const, test[4].tellname() is Sample::tellname with Sample being an undefined structure so "Name :" is rightfully printed then the memory in test[4]._name is printed and luckily the memory pointed by test[4]._name* is non null and is even a end string char.

So yeah you are lucky.

88877
  • 485
  • 3
  • 11
  • 1
    Hello 88877, welcome to SO. Please let code keep its formatting, by enclosing it withing back-ticks (`) or by padding the beginning with four spaces. You can do that automatically with either CTRL-K or with the {} button. – edmz Jan 06 '16 at 13:28
3

It sounds like you are wondering why the function is called. In memory, structs do not contain the functions inside them. Instead, one copy of the functions are placed somewhere in the executable. So when you are calling test[4].tellname() what is really happening is: The address test + (4 * sizeof(Sample)) is passed to the function tellname(). The value at that address is undefined.

Here is an example to give you an idea of what is going on:

#include <iostream>

struct astruct {
    int i = 0;
    void prnt()
    {
        std::cout << i << '\n';
    }
};

struct bstruct {
    int y = 100;
};

int main()
{
    bstruct b;
    ((astruct*)&b)->prnt();
    getchar();
    return 0;
}

Here prnt() is behind the scenes being passed the address of bstruct and treats it like the address of an astruct, since the first value in bstruct is 100, it prints 100. You can even simplify it to this:

#include <iostream>

struct astruct {
    int i = 0;
    void prnt()
    {
        std::cout << i << '\n';
    }
};

int y = 100;

int main()
{
    ((astruct*)&y)->prnt();
    getchar();
    return 0;
}
Alex
  • 316
  • 4
  • 12
  • Interesting, it is not about structs though. but I guess it's almost the same? – vmonteco Jan 06 '16 at 13:36
  • 1
    Classes and structs are basically the same thing. Class members are, by default, private and struct members are, by default, public. – Alex Jan 06 '16 at 13:38