复制构造函数不起作用

时间:2013-03-25 21:03:24

标签: c++ copy-constructor

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

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 InitDocument函数之外的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; }; lpacLines对象。我已经调试了这段代码,所有内容都在这里正确分配。

SECOND EDIT:在尝试转换所有非指针成员变量时,我现在遇到错误C2248:'CObject :: CObject':无法访问类中声明的私有成员' CObject的”。经过反思,这样的问题可能是推动我首先使用指针的原因。

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

{{1}}

1 个答案:

答案 0 :(得分:3)

现在您已经发布了完整的类定义,很明显您确实违反了Rule of Three如果您需要自己显式声明析构函数,复制构造函数或复制赋值运算符,您可能需要明确声明所有这三个。

你有一个复制构造函数和一个析构函数,但是没有复制的assignemnt。添加这些成员,你应该没事。

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);
}

您的构造函数分配内存,并为其指定成员。在代码的某处,您正在制作CMyDocument的副本。由于您没有复制赋值运算符,编译器无用地为您创建一个,只需复制指针,以便您有两个 CMyDocument个对象指向同一个CArrayCStringArray。然后,当其中一个被删除时,他们会删除CArrayCStringArray,而另一个CMyDocument会留下指向无效内存的无用指针。当你试图使用那个无效的记忆时,有时候,如果你运气好的话,你会看到曾经存在的东西。在这种情况下,空CArrayCStringArray。 (他们在删除时自行清空)。如果你不幸运,程序就会崩溃。