0

When I sought for memory leaks I found this interesting peculiarity. I have

class Perseptron :
public Neiron
{
private:
 Neiron** neirons;
 }

in header file of class. When neirons[i][0] initialized then I see in debugger that neirons[i][1,2...n] fields already initialized such values as neirons[i][0] field values before constructor neirons[i][1,2...n] initialization.

neirons = new Neiron*[layerCount];
for (int i=0;i<layerCount;++i)
{
    neirons[i] = new Neiron[this->eachLayerCount[i]];
    for (int j=0;j<this->eachLayerCount[i];++j)
    {
        if (i == 0) {
            neirons[i][j] = Neiron(2, this->inCount, this->eachLayerCount[i + 1], i, j);
            neirons[i][j].inX = this->inX;
        }
        else if(i!=layerCount-1) 
            neirons[i][j] = Neiron(2, this->eachLayerCount[i - 1], this->eachLayerCount[i + 1],i,j);
        else 
            neirons[i][j] = Neiron(2, this->eachLayerCount[i - 1], 1,i,j);
    } 
}

My Neiron constructors:

Neiron::Neiron(int limit,int inCount,int outCount,int layerN,int neironN)

Neiron::Neiron(){}

Why is that?

EDIT

MCVE

class Test{
public:
int fieldA;
Test(int a)
{
    fieldA = a;//when a=3, why already fieldA=2 ?
}
Test()
{

}
 };

int main()
{
int layers[] = { 3,4,2 };
int counter = 0;
Test** test=new Test*[3];
for (int i = 0;i < 3;++i)
{
    test[i] = new Test[layers[i]];
    for (int j = 0;j < layers[i];++j)
    {
        test[i][j] = Test(counter);
        counter++;
    }
}
for (int i = 0;i < 3;++i) delete[] test[i];
delete[] test;
return 0;
}
4
  • Why not use std::vector? Commented Mar 3, 2017 at 12:36
  • @NathanOliver, for me was very interesting work with dynamic memory... Commented Mar 3, 2017 at 12:40
  • are you also creating the array of pointers before this for loop? if not, then it's possible that you're accessing unallocated memory which triggers undefined behaviour. You cannot assign to neirons[i] before neirons is created. Commented Mar 3, 2017 at 13:40
  • @Kos, I just edited question Commented Mar 3, 2017 at 14:31

1 Answer 1

1

Creating object with new always implicitly calls constructor, it's a part of the standard and this approach is quite handy. So writing neirons[i] = new Neiron[this->eachLayerCount[i]]; means "create array with N objects of Neiron class and store pointer to that array into neirons[i]". As a result, dynamic buffer is allocated, N objects are created in it(constructor is called).

Current case doesn't differ much from creating a single object neirons[i] = new Neiron;, where you might get used to implicit constructor calling.

Related part of C++ standard:

Default constructors ... are called to create class objects of dynamic storage duration (3.7.4) created by a new-expression in which the new-initializer is omitted (5.3.4) ...

EDIT

I might have misinterpreted the question. It looks like you are wondering on some fields being initialized by the time when only default constructor is called, which doesn't do anything on them. There should be no magic, not initialized variable gets its value from the garbage left on dynamic memory. If you see some meaningful values instead of random stuff or zeroes, you might have put your new object into the memory, which has just been freed from being used for the same purpose. If you aren't convinced with this explanation, please create MCVE, so we can reproduce and explain scenario step by step.

EDIT 2

Thanks to clarifications, I see the concern now. Here is what is going within the MCVE:

test[i] = new Test[layers[i]];

Dynamic buffer is allocated and filled with layers[i] objects. Objects are created with default constructor, so their fields aren't initialized, but contain garbage left on the heap (e.g. fieldA of these objects is set to -842150451 or any other meaningless value).

for (int j = 0;j < layers[i];++j)
{
    test[i][j] = Test(counter);
    counter++;
}

This sample uses anonymous object in the right side, so it is actually an equivalent of this one:

for (int j = 0;j < layers[i];++j)
{
    Test temporaryObject(counter);
    test[i][j] = temporaryObject;
    counter++;
}

Program creates temporary object on stack using parametrized constructor, then initializes test[i][j] with it, destroys temporary object and repeats it for next i/j.

First iteration (i=0, j=0) allocates uninitialized buffer in stack to store temporary object and calls parametrized constructor for it, so you can see fieldA modified in constructor from garbage to zero. Then temporary object is used to init test[i][j] and is destroyed, freeing memory.

Second iteration (i=0, j=1) allocates exactly the same area of memory to store temporary object (you can verify it by inspecting &temporaryObject or checking this in parametrized constructor). Since this memory contains leftovers from previous usage as temporary object, you see constructor changing fieldA from 0 (left from previous iteration) to 1. And so on.

I want to stress, that process above is related to temporary object only. test[i][j] are initialized twice only:

  1. with random garbage during creation with test[i] = new Test[layers[i]];
  2. with actual value from temporary object with test[i][j] = Test(counter);
Sign up to request clarification or add additional context in comments.

5 Comments

I added MCVE to my question.
Nice! However, can't reproduce it locally. With VS2015 I always get some weird initial value for fieldA like -842150451 (which is 0xCDCDCDCD) until initialization line test[i][j] = Test(counter); is hit. What toolchain do you use?
VS2015 Update 2. Before first initialization it's -858993460. Then it equals to a-1....
So you see the following: once test[0][0] = Test(0); is executed, all test[0][x] has the fieldA set to zero. Once test[0][1] = Test(1); is executed, all test[0][x] (for x>=1) has fieldA set to one and so on, correct? Does console output with std::cout << "(" << i << ", " << j << "): " << test[i][j].fieldA << "\n"; right before test[i][j] = Test(counter); shows the same thing?
cout << test[i][j].fieldA << endl; shows '-84215045' nine times. But in case below I get -858993460 0 1 2 3 4 5 6 7. Test(int a) { // cout << fieldA << endl; fieldA = a; }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.