为什么std :: map在通过operator []创建时重新赋值?

时间:2015-01-29 22:49:19

标签: c++ pointers visual-studio-2005 hierarchy stdmap

我实现了一个在Parent内存储许多std::map个对象的类。每个Parent都有一个ChildChild有一个指向Parent的指针,Parentstd::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_Aparent_A创建child_A并将child_A.parent指针设为&parent_A }。然后由于某种原因parent_A被破坏,parent_B取而代之。但它会存储相同的旧数据,包括child_Achild_A.parent仍然指向parent_A

问题是,为什么会发生以及如何解决这个问题?

该项目的一个要求是使用vs2005及其原生编译器。

提前谢谢!

1 个答案:

答案 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可以使用什么。