带有自定义对象的向量:当我想使用.at方法接收时,会崩溃

时间:2013-08-10 20:50:47

标签: c++

我有一个名为CConfig的类,我正在创建新对象:

std::vector< CConfig > docs;

CConfig newfile( "somefile.xml", "root" );
printf("%s", newfile.GetTagValue( "servername" )); // this works
docs.push_back( newfile );

当我使用.at方法

获取此对象时
CConfig file = docs.at(0);
printf("%s", file.GetTagValue( "servername" )); // this crashes

问题出在哪里?

(对不起,如果格式化错误,但目前我不使用javascript,因为我的带宽已经结束,最大速度是1kb / s所以我稍后会尝试修复它)

CConfig.h:

class CConfig
{
    TiXmlDocument       m_doc;
    TiXmlElement*       m_pRoot;
    bool                m_bIsLoaded;

public:
                    CConfig                     ( void ) {};
                    CConfig                     ( const char * pszFileName, const char * pszRootName );
                    ~CConfig                    ( void ) {};

const char*         GetTagValue                 ( const char * pszTagName );
const char*         GetTagAttribute             ( const char * pszTagName, const char * pszAttributeName );
TiXmlElement*       GetRootElement              ( void )    { return m_pRoot; };
bool                IsAvailable                 ( void )    { return m_bIsLoaded; };
};

CConfig.cpp

#include "CConfig.h"

CConfig::CConfig( const char * pszFileName, const char * pszRootName )
{
    m_bIsLoaded = m_doc.LoadFile( pszFileName );
    if( m_bIsLoaded )
        m_pRoot = m_doc.FirstChildElement( pszRootName );
}

const char * CConfig::GetTagValue( const char * pszTagName )
{
    if( m_bIsLoaded && m_pRoot )
    {
        TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
        if( element )
            return element->GetText();
    }
}

const char * CConfig::GetTagAttribute( const char * pszTagName, const char * pszAttributeName )
{
    if( m_bIsLoaded && m_pRoot )
    {
        TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
        if( element )
            return element->Attribute( pszAttributeName );
    }
}

我正在使用tinyxml

2 个答案:

答案 0 :(得分:3)

您的问题是指向旧内存的指针。将项添加到数组时,将复制该项。稍后您离开该范围并销毁原件,但问自己副本中的指针指向哪里?仍然是第一个(现在删除)对象的内存。糟糕,

最简单的修复(避免大型复制操作)是将m_doc转换为共享指针(在C ++ 11中的标准中可用,或者在C ++ 03中通过Boost提供)。然后,那将为你处理一切明智的规则。并且由于底层内存不会移动,m_pRoot将保持有效,直到最后一个副本被删除。

答案 1 :(得分:2)

如果副本空间不是问题,请通过正确添加复制构造函数来修复违反规则3:

CConfig(const CConfig& obj) 
   : m_doc(obj.m_doc)
   , m_bLoaded(obj.m_bLoaded)
   , m_pRoot()
{
   if (m_bLoaded)
      m_pRoot = m_doc.GetRootElement();
}

赋值运算符也可能是有序的,但是如果你不需要它,可以通过将它(但不是实现它)声明为private来隐藏它,或者使用C ++ 11 delete属性特征。

有趣的是,您甚至不需要m_bLoaded成员。非NULL根指针可以指示您的加载状态,但这是一个单独的问题。这至少足以让你开始运行。