为什么std::map在通过operator[]创建的时候实例化它的值
Why does std::map reinstantiate it's value when it's created through operator[]
我实现了一个 class,它在 std::map
中存储了一些 Parent
个对象。每个 Parent
都有一个 Child
。 Child
有一个指向它的 Parent
的指针,它在 Parent
的构造函数中设置。
它是这样的:我调用 std::map::operator[]
,它调用 Parent
的构造函数,它将 child.parent
设置为 this
,而 returns 我Parent
。应该没问题,但如果您将返回的 Parent
的地址与其 child
存储的地址进行比较,它们将不匹配。这意味着 Child
有一个无效的指针。
所以当我通过std::map::operator[]
初始化Parent
时,Child
的parent
指针无效。
一个小演示:
//
// 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
时引发访问冲突。在真实应用程序上调试此问题表明从 std::map::operator[]
返回的 Parent
与用于创建 Child
的不同,但 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 及其本机编译器。
提前致谢!
当您使用时:
Parent parent = testMap[ 42 ];
您正在获取地图中 Parent
的副本。当然,这个parent
对象中的child
指向的是不存在的Parent
您需要实现 Parent
的复制构造函数,它为包含的 child
.
做正确的事情
Parent(Parent const& copy)
{
uniqueId = std::rand();
child.parent = this;
child.originalParentUniqueId = uniqueId;
}
嗯...不确定 copy
中可以使用什么。
我实现了一个 class,它在 std::map
中存储了一些 Parent
个对象。每个 Parent
都有一个 Child
。 Child
有一个指向它的 Parent
的指针,它在 Parent
的构造函数中设置。
它是这样的:我调用 std::map::operator[]
,它调用 Parent
的构造函数,它将 child.parent
设置为 this
,而 returns 我Parent
。应该没问题,但如果您将返回的 Parent
的地址与其 child
存储的地址进行比较,它们将不匹配。这意味着 Child
有一个无效的指针。
所以当我通过std::map::operator[]
初始化Parent
时,Child
的parent
指针无效。
一个小演示:
//
// 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
时引发访问冲突。在真实应用程序上调试此问题表明从 std::map::operator[]
返回的 Parent
与用于创建 Child
的不同,但 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 及其本机编译器。
提前致谢!
当您使用时:
Parent parent = testMap[ 42 ];
您正在获取地图中 Parent
的副本。当然,这个parent
对象中的child
指向的是不存在的Parent
您需要实现 Parent
的复制构造函数,它为包含的 child
.
Parent(Parent const& copy)
{
uniqueId = std::rand();
child.parent = this;
child.originalParentUniqueId = uniqueId;
}
嗯...不确定 copy
中可以使用什么。