0

我有一些创建文档数组的代码。每个文档对象都有一个文档范围的值数组,以及一个包含所有文档数据的单个文件数组(称为行,因为每个文件都是我正在读取的源文件中的一行)。当我尝试将文档对象添加到数组时,它在下面调用我的复制构造函数:

CMyDocument::CMyDocument(CMyDocument& cSourceDoc)
{
    m_lpastrFields = new CStringArray;
    m_lpacLines = new CArray<CMyLine, CMyLine>;
    int nCount;
    int nSize;
    nSize = static_cast<int>(cSourceDoc.GetFields()->GetSize());
    for (nCount = 0; nCount < nSize; nCount++)
    {
        m_lpastrFields->Add(cSourceDoc.GetFields()->GetAt(nCount));
    }
    nSize = static_cast<int>(cSourceDoc.GetLines()->GetSize());
    for (nCount = 0; nCount < nSize; nCount++)
    {
        m_lpacLines->Add(cSourceDoc.GetLines()->GetAt(nCount));
    }
    m_strDocDate = cSourceDoc.GetDocDate();
    m_nDocID = cSourceDoc.GetDocID();
    m_strDocType = cSourceDoc.GetDocType();
}

问题是,当我稍后尝试通过从文档数组中拉取文档来访问文档时,我上面复制的两个数组是空的。似乎已初始化并具有内存地址,但它们不包含数据。虽然填充了成员变量。我不确定我是否复制不正确,或者问题是否出在其他地方。

编辑:常规构造函数如下所示:

CMyDocument::CMyDocument()
{
    m_lpastrFields = new CStringArray;
}

在这种情况下,我没有新建m_lpacLines对象,因为它是通过一个名为 InitDocument 的函数传递到 MyDocument 对象的。我不妨把它包括在这里。(一些不必要的细节,比如我解析strLine变量以提取所有值的方式,为简洁起见被修剪了。

void CMyDocument::InitDocument(CMyColumns* lpcColumns, CString strLine, CArray<CMyLine, CMyLine>* lpacLines)
{
    CString strValue;
    CString strComma = ",";
    int     nPos = 0;

    m_lpacLines = lpacLines;

    while (-1 != nPos)
    {
        strValue = strLine.Tokenize(strComma, nPos);
        m_lpastrFields->Add(strValue);
    }
    m_strDocDate = m_lpastrFields->GetAt(lpcColumns->GetDocDateIndex());
    CString strDocID = m_lpastrFields->GetAt(lpcColumns->GetDocIDIndex());
    m_nDocID = atoi(strDocID);
    m_strDocType = m_lpastrFields->GetAt(lpcColumns->GetDocTypeIndex());
}

需要明确的是,每次循环时,我都会new在函数之外调用 lpacLines 对象。InitDocument我已经调试了这段代码,并且这里的所有内容都被正确分配。

第二次编辑:在尝试转换这些所有非指针成员变量时,我现在遇到错误 C2248:'CObject::CObject':无法访问在类'CObject'中声明的私有成员。回想起来,像这样的问题可能是促使我首先使用指针的原因。

第三次编辑:这是类声明:

class CMyDocument
{
    public:
        CMyDocument();
        ~CMyDocument();
        CMyDocument(CMyDocument& cSourceDoc);
        void    InitDocument(CMyColumns* lpcColumns, CString strLine, CArray<CMyLine, CMyLine>* lpacLines);
        inline  CString GetDocDate(void) {return(m_strDocDate);};
        inline  int     GetDocID(void) {return(m_nDocID);};
        inline  CString GetDocType(void) {return(m_strDocType);};

        inline  CStringArray*   GetFields(void) {return(m_lpastrFields);};
        inline  CArray<CMyLine, CMyLine>*   GetLines(void) {return m_lpacLines;};
    private:
        CArray<CMyLine, CMyLine>*   m_lpacLines;
        CStringArray*   m_lpastrFields;

        CString             m_strDocDate;
        int                 m_nDocID;
        CString             m_strDocType;
};
4

1 回答 1

3

Now that you've posted the full class definition, it is clear that you are indeed violating the Rule of Three: If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.

You have a copy constructor, and a destructor, but no copy assignemnt. Add these members and you should be fine.

CMyDocument& operator=(CMyDocument cSourceDoc) {
    swap(cSourceDoc);
    return *this;
}

void swap(CMyDocument& cSourceDoc) {
   using std::swap;
   swap(m_lpacLines, cSourceDoc.m_lpacLines);
   swap(m_lpastrFields, cSourceDoc.m_lpastrFields);
   swap(m_strDocDate, cSourceDoc.m_strDocDate);
   swap(m_nDocID, cSourceDoc.m_nDocID);
   swap(m_strDocType, cSourceDoc.m_strDocType);
}

Your constructor allocates memory, and makes a member point at it. Somewhere in your code you are making a copy of a CMyDocument. Since you have no copy assignment operator, the compiler uselessly made one for you, that simply copies the pointer, so that you then have two CMyDocument objects pointing at the same CArray and CStringArray. Then, when one of them is deleted, they delete the CArray and CStringArray, and the other CMyDocument is left with useless pointers that point at invalid memory. When you are attempting to use that invalid memory, sometimes, if you get lucky you'll see what used to be there. In this case, the empty CArray and CStringArray. (They empty themselves right as they are deleted). If you weren't lucky, the program would have simply crashed.

于 2013-03-26T23:37:43.203 回答