我实现了一个在Parent
内存储许多std::map
个对象的类。每个Parent
都有一个Child
。 Child
有一个指向Parent
的指针,Parent
在std::map::operator[]
的构造函数中设置。
它是这样的:我致电Parent
,它调用child.parent
的构造函数,将this
设置为Parent
,然后返回Parent
。应该没问题,但如果您将返回的child
地址与Child
存储的地址进行比较,则它们将不匹配。意味着Parent
具有无效指针。
因此,当我初始化std::map::operator[]
到Child
时,parent
的{{1}}指针无效。
一个小小的演示:
//
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <cstdlib>
// Just some forward declaration
struct Parent;
/**
* Child dummy (just to model my data structure)
*/
struct Child
{
/**
* Pointer to it's parent (that gets initialized in Parent's constructor)
*/
Parent * parent;
/**
* Original parent's uid
*/
int originalParentUniqueId;
};
/**
* Parent dummy to model my data scructure
*/
struct Parent
{
/**
* Child object that *should* reference (this) parent through a pointer
*/
Child child;
/**
* Some parent field for demonstration
*/
const char * someParentData;
/**
* What's our name?
*/
int uniqueId;
Parent()
{
uniqueId = std::rand();
// Luke, I'm your father!
child.parent = this;
child.originalParentUniqueId = uniqueId;
// We'll be GLaD we get burned (somewhere inside std::map)
someParentData = "The cake is a lie.";
// Our child will be adopted by another Parent, but he will always remember us.
// (by keeping that child.parent ptr pointing at THIS instance)
}
};
//
// Test case
//
#include <map>
#include <ctime>
#include <iostream>
typedef std::map<int, Parent> test_map_t;
int _tmain(int argc, _TCHAR* argv[])
{
std::srand( std::time( NULL ) );
//
// Testing without std::map first.
//
Parent testParent;
if( testParent.child.parent != &testParent )
{
std::cout << "The pointers do NOT match. Impossiburu!\n"; // can't get here
}
else
std::cout << "The pointers match. Things work as expected.\n";
std::cout << "\n";
//
// Let's test std::map now
//
test_map_t testMap;
Parent parent = testMap[ 42 ]; // life, the universe and everything...
if( parent.child.parent != &parent )
{
std::cout << "The pointers do NOT match.\nMight crash in case of access violation...\n";
std::cin.get();
}
else
std::cout << "The pointers match. Houston, we have a problem.\n"; // can't get here
std::cout
<< "parent.uniqueId: \""
<< parent.uniqueId << "\"\n"
<< "parent.child.originalParentUniqueId: \""
<< parent.child.originalParentUniqueId << "\"\n\n"
;
std::cout
<< "parent.someParentData: \""
<< parent.someParentData << "\"\n"
<< "parent.child.getSomeParentData(): \""
<< parent.child.parent->someParentData << "\"\n"
;
std::cin.get();
return 0;
}
输出:
The pointers match. Things work as expected.
The pointers do NOT match.
Might crash in case of access violation...
parent.uniqueId: "1234321"
parent.child.originalParentUniqueId: "1234321" <- Match.
parent.someParentData: "The cake is a lie."
parent.child.getSomeParentData(): " <- Access violation reading
address 0xcccccccc (literally),
no further output
访问parent.child.parent -> someParentData
时会引发访问冲突。在真实应用上调试此问题表明,Parent
返回的std::map::operator[]
与用于创建Child
的{{1}}不同,但Child
是同一个对象在原始的Parent
构造期间实例化了。
它是这样的:您致电operator[]
,创建parent_A
,parent_A
创建child_A
并将child_A.parent
指针设为&parent_A
}。然后由于某种原因parent_A
被破坏,parent_B
取而代之。但它会存储相同的旧数据,包括child_A
,child_A.parent
仍然指向parent_A
。
问题是,为什么会发生以及如何解决这个问题?
该项目的一个要求是使用vs2005及其原生编译器。
提前谢谢!
答案 0 :(得分:1)
使用时:
Parent parent = testMap[ 42 ];
您将在地图中获得Parent
的副本。当然,此child
对象中的parent
指向不存在的Parent
。
您需要实现Parent
的复制构造函数,为包含的child
执行正确的操作。
Parent(Parent const& copy)
{
uniqueId = std::rand();
child.parent = this;
child.originalParentUniqueId = uniqueId;
}
嗯......不确定copy
可以使用什么。