C++:指向 std::map 的指针的奇怪行为

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

我需要与内部 class 共享一些变量 (myMap)。我尝试使用以下方法来做到这一点:

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" );
}

问题是我无法再访问 objArr[ 0 ].secondClass.myMapPtr。您可以编译此代码并查看它 returns 错误:"EXC_BAD_ACCESS" 在行:

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

这是怎么回事? objArr 应该在其中存储创建的对象。为什么它不能像这样工作?

更新 2: @rcrmn,谢谢。但是我不明白为什么当我在 std::vector 中添加另一个元素时它破坏了我以前的指针:

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" );

问题出在最后一行。但为什么?我没有更改 objArr 的第一个元素,为什么我无法访问第一个元素? ("int i2" 行)。

UPD 3 即使我这样做:

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" );

我也有这个错误,但是为什么...我在范围结束后存储了一个指向 &objArr[0].myMap 的指针,它不应该改变元素了。我的错在哪里?

因为向量存储而你没有遵守三原则。

在您的主 class 中,您正在范围内创建一个由名称 newObj 引用的对象。在其构造函数中,它采用指向其 std::map 的指针并将其存储在内部 class.

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

问题是 push_back 按原样复制对象,内部对象对 std::map 的引用仍然引用旧对象的映射。因此,当离开作用域时,newObj 被销毁,您在其中的引用现在无效。

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

我认为你最好的选择是覆盖 TestClass 的复制构造函数,因此内部 class 引用正确的 std::map.

编辑:

问题是您是从 java 的角度来看待它的。在 C++ 中你没有垃圾收集器,你有作用域。不在共享内存中创建的对象(例如使用 new),如方法中的对象变量,在程序流进入作用域时创建,并在程序流离开时销毁。

因此,如果您在对象内部保留对映射的引用,当您离开由 {} 分隔的范围时对象被销毁,该引用将不再指向有效的内存位置。

编辑 2:

嗯,实际上,现在我仔细想想,std::vector 很有可能在增加数组大小时重新分配您的对象。在这种情况下,对地图的引用将不再有效。

您可以通过预分配数组来验证此行为:

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" );

但是你真的应该为此使用共享内存。