简体   繁体   中英

C++: strange behaviour with the pointers to std::map

I need to share some variable ( myMap ) with the inner class. I tried to do it using following approach:

class SecondClass {
public:
    std::map< std::string, short > *myMapPtr;
};

class TestClass {
public:
    SecondClass secondClass;
    std::map< std::string, short > myMap;
    TestClass() {
        printf( "consturctor of TextClass\n" );
        secondClass.myMapPtr = &myMap;
    }
    ~TestClass() {
        printf( "desturctor of TextClass\n" );
    }
};

int main() {
    std::vector< TestClass > objArr;
    {
        TestClass newObj;
        objArr.push_back( newObj );
    }
    int i = objArr[ 0 ].secondClass.myMapPtr->count( "test" );
}

The problem is that I don't have access to objArr[ 0 ].secondClass.myMapPtr anymore. You can compile this code and see that it returns an error: "EXC_BAD_ACCESS" on the line:

int i = objArr[ 0 ].secondClass.myMapPtr->count( "test" );

What's wrong here? objArr should stores created objects inside it. Why it doesn't work like this?

UPD 2: @rcrmn, thanks. But I don't understand why when I add another element in my std::vector it brokes my previous pointer:

std::vector< TestClass > objArr;
{
    TestClass newObj;
    objArr.push_back( newObj );
    objArr[ 0 ].secondClass.myMapPtr = &objArr[ 0 ].myMap;
}
int i1 = objArr[ 0 ].secondClass.myMapPtr->count( "test" );
{
    TestClass newObj;
    objArr.push_back( newObj );
    objArr[ 1 ].secondClass.myMapPtr = &objArr[ 1 ].myMap;
}
int i2 = objArr[ 0 ].secondClass.myMapPtr->count( "test" );

the problem is on the last line. But why? I didn't change the first element of objArr why I haven't access to the first element? ("int i2" line).

UPD 3 Even if I do something like this:

std::vector< TestClass > objArr;
{
    TestClass newObj;
    objArr.push_back( newObj );
}
objArr[ 0 ].secondClass.myMapPtr = &objArr[ 0 ].myMap;
{
    TestClass newObj;
    objArr.push_back( newObj );
}
objArr[ 1 ].secondClass.myMapPtr = &objArr[ 1 ].myMap;
int i = objArr[ 0 ].secondClass.myMapPtr->count( "test" );

I also have that error but why... I store a pointer to &objArr[ 0 ].myMap after the scope ends and it shouldn't change the address of the element anymore. Where's my fault?

In your main class you are creating an object referenced by the name newObj inside an scope. In its constructor, it takes a pointer to its std::map and stores it in the inner class.

TestClass() {
    printf( "consturctor of TextClass\n" );
    secondClass.myMapPtr = &myMap; // <- the problem
}

The problem is that push_back copies the object as is, with the inner object's reference to the std::map still referencing the old object's map. So, when leaving the scope, the newObj is destroyed and your reference inside is now invalid.

{
    TestClass newObj;
    objArr.push_back( newObj );
}

Your best option I think it would be to override the copy constructor of the TestClass so the inner class references the correct std::map .

Edit:

The problem is you are looking at it from a java perspective. In C++ you don't have garbage collector, you have scopes. Objects not created in shared memory (using new, for example), like object variables in a method, are created when the program flow enters the scope and are destroyed when it leaves it.

So, if you keep a reference to the map inside the object, when the object is destroyed when you leave the scope delimited by {} , that reference will no longer be to a valid memory location.

Edit 2:

Well, actually, now that I think on it, it's quite possible that std::vector is reallocating your objects when it increases the size of the array. In that case, the references to the map would no longer be valid.

You can verify this behaviour preallocating the array:

std::vector< TestClass > objArr;
objArr.reserve(2);
{
    TestClass newObj;
    objArr.push_back( newObj );
}
objArr[ 0 ].secondClass.myMapPtr = &objArr[ 0 ].myMap;
{
    TestClass newObj;
    objArr.push_back( newObj );
}
objArr[ 1 ].secondClass.myMapPtr = &objArr[ 1 ].myMap;
int i = objArr[ 0 ].secondClass.myMapPtr->count( "test" );

But you should really use shared memory for this.

因为矢量存储副本,并且您没有遵守“三规则”。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM