Я реализую класс, в котором хранится количество объектов Parent
внутри std::map
. Каждый Parent
имеет Child
. То, что Child
имеет указатель на его Parent
, который установлен в конструкторе Parent
.Почему std :: map восстанавливает его значение, когда он создается с помощью оператора []
Это выглядит следующим образом: я называю std::map::operator[]
, он вызывает конструктор Parent
«s, который устанавливает child.parent
к this
, и возвращает мне Parent
. Должно быть хорошо, но если вы сравните возвращенный адрес Parent
с адресом, который находится в магазинах child
, они не совпадают. Это означает, что Child
имеет недопустимый указатель.
Так что, когда я инициализирую Parent
через std::map::operator[]
, это Child
's 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
. Отладка этой проблемы в реальном приложении показала, что Parent
, возвращенный с std::map::operator[]
, отличается от того, который использовался для создания 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' не реализует« Правило 3 »: http: //stackoverflow.com/questions/4172722/what-is-the-rule-of-three – PaulMcKenzie