4

我的目标是创建一个类,它将从它创建的每个实例添加到静态成员容器中,以便可以轻松访问所有实例。

上下文是一个游戏,其中对象在Game.init()函数中创建,然后添加到容器中。然后Game.update(),andGame.Draw()函数遍历容器以访问和操作对象。

我希望构造函数和解构函数来处理这些任务,而不是手动向容器添加或删除对象。

当对象(此代码中的框)被复制或分配时,指针变得无效,这是有问题的。使用对象容器而不是指向对象容器的指针会导致制作过多的副本,并且我无法使用引用进行此操作。我正在寻找一些关于如何改进此代码以避免这些问题的提示(不需要使用指向对象的容器,实际上我宁愿避免使用指针但没有设法让它工作他们):

#include <list>
#include <iostream>

class Box
{
    private:
        std::list <Box*>::iterator iter;
    public:
        static std::list <Box*> List;
        Box() {
            List.push_front(this);
            iter = List.begin();
            std::cout << "Constructing box." << std::endl;
        }
        ~Box() {
            std::cout << "Trashing box." << std::endl;
            List.erase(iter);
        }
        void lookInside() {
            std::cout << "It's empty." << std::endl;
        };
};

std::list <Box*> Box::List;

int main()
{
    Box Box_1;
    Box Box_2;
    Box Box_3;

    Box_1 = Box_2; // causes problems!

    for (auto iter : Box::List) {
        iter->lookInside();
    }

    std::cout << "The list contains " << Box::List.size() << " boxes." << std::endl;

    return 0;
}
4

1 回答 1

2

You're violating the rule of three/five.

You'll undoubtedly need to overload assignment and copy construction (at the very least) to make your class work as desired. The default copy constructor will just copy the iterator so you'll end up with the second object containing a copy of the original iterator, pointing to the original object, so when either copy gets destroyed, that item gets removed from your collection.

Obviously, what you want is to add a new object to your collection, and have that object hold the iterator to the new object in the collection when copy construction is done.

Likewise, the default assignment operator will copy the iterator from the source to the target. You probably just want to leave the iterator unchanged (i.e., still referring to the same object in the collection, since assignment results in the same object holding a different value).

#include <list>
#include <iostream>

class Box
{
    private:
        std::list <Box*>::iterator iter;
    public:
        static std::list <Box*> List;
        Box() {
            List.push_front(this);
            iter = List.begin();
            std::cout << "Constructing box." << std::endl;
        }
        ~Box() {
            std::cout << "Trashing box." << std::endl;
            List.erase(iter);
        }
        void lookInside() {
            std::cout << "It's empty." << std::endl;
        };

        // JVC: added next two overloads:
        Box &operator=(Box const &src) { 
            // don't assign anything.
            return *this;
        }
        Box(Box const &other) { 
            List.push_front(this);
            iter = List.begin();
            std::cout << "Copy constructing box.\n";
        }
};

std::list <Box*> Box::List;

int main()
{
    Box Box_1;
    Box Box_2;
    Box Box_3;

    Box_1 = Box_2; // No longer causes problem!

    for (auto iter : Box::List) {
        iter->lookInside();
    }

    std::cout << "The list contains " << Box::List.size() << " boxes." << std::endl;

    return 0;
}

As an aside: this whole design is probably a mistake. The code above covers for the bugs at a relatively microscopic level, but does nothing to correct the basic problem of the design.

于 2013-05-11T20:32:49.720 回答