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" );
但是你真的应该为此使用共享内存。
我需要与内部 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" );
但是你真的应该为此使用共享内存。