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

时间:2015-02-09 11:16:36

标签: c++ pointers gcc stdmap

我需要与内部类共享一些变量( 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 。您可以编译此代码并看到它返回错误:&#34; EXC_BAD_ACCESS&#34;在线:

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

这里有什么问题? objArr应该在其中存储创建的对象。为什么它不能这样工作?

UPD 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的第一个元素,为什么我无法访问第一个元素? (&#34; int i2&#34; line)。

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

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

2 个答案:

答案 0 :(得分:3)

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

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

问题是push_back按原样复制对象,内部对象对std::map的引用仍然引用旧对象的地图。因此,当离开范围时,newObj将被销毁,您的内部引用现在无效。

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

我认为最佳选择是覆盖TestClass的复制构造函数,以便内部类引用正确的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" );

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

答案 1 :(得分:1)

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