复制构造函数不起作用,无法修改副本

时间:2014-01-04 23:53:55

标签: c++ constructor copy

我需要帮助,因为我一直在努力解决这个问题,但我真的不知道该怎么做。问题是我做了一个复制构造函数;它复制得很好,但是当我想通过在末尾添加元素来修改副本时它不起作用,则不会打印元素。

当我在开头添加元素时,当我尝试使用方法add_at添加元素时,它会起作用,它会在两个列表中添加元素。我真的不知道问题出在哪里;它是在构造函数中还是在方法中?

你可以认为我的代码很奇怪,但我不得不像这样添加方法......

以下是代码:

.h文件

class CList
{
    SElement* first;
    SElement* last;
    int lenght;
    int value;

    public:
        CList();
        CList(CList const& clist);
        ~CList();

        // add methods
        void add(int value);
        void add_first(int value);
        void add_at(int at, int value);
        void addObject(void* object);
        void addObject_first(void* object);
        void addObject_at(int at, void* object);

        // delete methods
        void del_last();
        void del_first();
        void del_index(int index);
        void del_element(void* value);
        void del_ielement(int& value);

        // getery
        int iget_lenght();
        int iget_element(int const index);
        SElement* sget_element(int index);
        void* get_element(int index);

        void set_element(int const index, int& value);

        void pop();
        void push(int value);

        void printCList();

    private:
        void priv_push(int & value);
};

.cpp

中涉及的方法
CList::CList()
{
    first = new SElement;
    last = new SElement;
    first = last = NULL;
    lenght = 0;
    value = 0;
}

CList::CList(CList const& clistcopy)
{
    this->lenght = clistcopy.lenght;
    this->value = clistcopy.value;
    first = new SElement;
    last = new SElement;
    // pointer = last = NULL;
    *first = *clistcopy.first;
    *last = *clistcopy.last;
}

CList::~CList()
{
    SElement* el;
    while (first)
    {
        el = first->next;
        delete first;
        first = el;
    }
    delete last;
}

// ADD FIRST
void CList::addObject_first(void* object)
{
    SElement* el = new SElement;

    el->next = first;
    el->previous = NULL;
    el->object = object;

    if (first != NULL)
        first->previous = el;
    first = el;

    if (!last) last = first;
    lenght++;
}
void CList::add_first(int wartosc)
{
    value = wartosc;
    int* wsk = &value;
    int* pnt = new int;
    *pnt = *wsk;
    addObject_first(pnt);
}

// ADD LAST
void CList::addObject(void* object)
{
    if (!last)
    {
        SElement* el = new SElement;
        el->object = object;
        el->next = NULL;
        el->previous = NULL;
        first = last = el;
    }
    else
    {
        SElement* el = last;
        el->next = new SElement;
        el = el->next;
        el->next = NULL;
        el->previous = last;
        el->object = object;
        last = el;
        el = NULL;
    }

}
void CList::add(int wartosc)
{
    value = wartosc;
    int* wsko = &value;
    int* pnt = new int;
    *pnt = *wsko;
    addObject(pnt);
}

// ADD AT
void CList::addObject_at(int index, void* value)
{
    SElement* el2 = new SElement;
    if (index - 1 == 0)
        addObject_first(value);
    else if (index - 1 == lenght)
        addObject(value);
    else if (index < 0 || index > lenght)
        cout << "blad : nie mozesz dodac na indeks poza lista" << endl;
    else
    {
        SElement* el = sget_element(index - 1);
        el2->next = el->next;
        el2->previous = el;
        el2->object = value;
        el->next = el2;
        el->next->previous = el2;
        if (!(el2->next)) last = el2;
        lenght++;
    }
}

void CList::add_at(int at, int wartosc)
{
    value = wartosc;
    int* wsko = &value;
    int* pnt = new int;
    *pnt = *wsko;
    addObject_at(at, pnt);
}
void CList::printCList()
{
    if (first == NULL)
        cout << "Lista jest pusta" << endl;
    else
    {
        SElement* el;
        el = first;
        while (el->next != NULL)
        {
            cout << el->get_value();
            cout << " ";
            el = el->next;
        }
        cout << el->get_value();
    }
    cout << endl;
}

主要

int main()
{
    CList list = CList();

    list.add_first(1);
    list.add_first(0);
    list.add_first(2);
    list.add_first(4);
    list.add(5);
    list.add(10);

    CList list2 = CList(list);

    list.printCList();
    list2.printCList();
    list2.add(100);
    list2.add(150);

    cout << list.iget_lenght()  << endl;
    cout << list2.iget_lenght() << endl;
    list.printCList();
    list2.printCList();

    system("pause");
    return 0;
}

2 个答案:

答案 0 :(得分:0)

在我看来,在尝试查明问题之前,您应该清理代码。

例如:

CList::CList()
{
    first = new SElement; // <-- these two lines
    last = new SElement;  // <-- are useless
    first = last = NULL;
    lenght = 0;
    value = 0;
}

此外,复制构造函数的语义错误。在这里,您只需复制头部和尾部指针,但不要复制列表中的对象。 更确切地说,你似乎试图复制它们,但你的代码也是错误的:

first = new SElement;      // allocate an SElement
*first = *clistcopy.first; // copy model's element into it
// since you don't assign first to a permanent variable, it is lost forever

无论如何,即使使用正确的头/尾副本,您的副本仍会引用存储在模型中的对象 修改“副本”也会改变原始列表的元素,这是完全错误的 此外,由于lengthvalue字段确实是重复的,因此只要修改了列表中的任何一个,它们就会与链接元素的状态不一致。

要制作真正的复制构造函数,您需要浏览列表并复制每个元素。 例如:

CList::CList(CList const& clistcopy)
{
    // create an empty list
    this->lenght = 0;
    this->value = 0;
    this->first = this->last = NULL;

    // browse through all elements of the model
    for (SElement * elt = clistcopy->first ; elt != NULL ; elt = elt->next)
    {
        // create a copy of each element
        elt_copy = new SElement (elt);

        // and insert it into the copy of the list
        this->add (elt_copy);
    }
}
编辑:这只是伪C ++来说明原理。我怀疑它甚至会在其复杂状态下编译。

我不知道这是否足以解决您的所有问题,但这肯定会从您的复制构造函数中删除一个主要的设计缺陷。

答案 1 :(得分:0)

There are deep copies and shallow copies.你已经做了一些介于两者之间的东西,并且有两者的缺点。

在深层副本中(这似乎是您的想法),将复制整个链接列表。

在浅拷贝中,只复制列表中的指针,这样两个CList就可以共享一个链表。

在您的版本中,您复制第一个和最后一个元素(鲁莽地假设它们存在)并分享其余元素。

阅读复制链表,并实施深层复制。