0

我有一个名为 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; };
};

配置文件

#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

4

2 回答 2

3

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

最简单的修复(同时避免大型复制操作)是制作m_doc共享指针(在 C++11 的标准中可用,或通过 C++03 中的 Boost)。然后,这将为您明智地处理 3 规则。并且由于底层内存不会移动,m_pRoot因此在最后一个副本被删除之前将保持有效。

于 2013-08-10T21:13:59.730 回答
2

如果复制空间不是问题,则通过正确添加复制构造函数来修复您的三规则违规:

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++11delete属性功能。

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

于 2013-08-10T21:21:00.453 回答