c++ storing an object into an array of objects wit

2019-01-28 23:42发布

I am trying to create an object and everytime I create an object, I then store that object in a static class variable that is an array of all of the objects created.

I am new to c++ and have no idea how to accomplish this. I have done it in Java before, but I am stuck here.

Take this for example purposes:

class Rectangle
{
    private:
        int width;
        int length;
        // Code to create an array of Rectangle Objects 
        // that hold all the the Rectangles ever created

    public:
        Rectangle();
        Rectangle(int x, int y);
};

Rectangle::Rectangle()
{
    width = 0;
    length = 0;
    // code to add an instance of this object to an array of Rectangle Objects
}

Rectangle::Rectangle(int x, int y)
{
    width = x;
    length = y;
    // code to add an instance of this object to an array of Rectangle Objects
}

Is this possible?

标签: c++ class object
2条回答
走好不送
2楼-- · 2019-01-29 00:07

Since you have to use an array to keep all objects you have to define a constant maximum size, since the size of an array is fixed and cannot be changed. This means that you also have to define a variable that keeps track of how many elements the array has, so that you don't exceed its boundaries.

const int MAX_SIZE = 100;

class Rectangle
{
    private:
        int width;
        int length;

        static Rectangle* all_rectangles[MAX_SIZE];
        static int rectangle_count;

    public:
        Rectangle();
        Rectangle(int x, int y);

};

Then you define the static variable and add the objects to the array in the Rectangle constructor, for example:

//Define static variables
Rectangle* Rectangle::all_rectangles[MAX_SIZE];
int Rectangle::rectangle_count = 0;

//Constructor
Rectangle::Rectangle () {
    all_rectangles[rectangle_count] = this;
    rectangle_count++;
}

Since the array with rectangles (and its components) is private, you can only reach it from within the class. You can however define functions that are public, to reach the rectangles private variables. You can get the width of a rectangle by declaring a function

static int getWidth(int a){
    return all_rectangles[a]->width; 
}

and call it by cout << Rectangle::getWidth(2) // Get width of second element in array

However vectors are preferable to use before arrays since they are expandable and includes many build-in functions, such as add and remove elements.

查看更多
走好不送
3楼-- · 2019-01-29 00:17

Nowadays we tend to avoid plain array and normal pointers.

So go for smart pointers and STL containers. As your objects will live and die, a vector may not be soon sparse, having lots of holes corresponding to the (deleted) objects you do not use anymore.

Another solution would be an unordered map (hash table). We then need a key. We will not think about transforming the value of a (the this) pointer to a int or long as it is a very dangerous way to go.

So we must pay for some unique id ( see boost uuid ). This is also costly for the computing time but all this mechanism will save you time ( for writing code documentation ).

We then need a smart pointer. As you want to keep track of all the object created we will go for a mandatory "factory" function to create your objects. As they may not be uniquely owned the only choice left for the factory function is to reject a shared pointer.

This is not directly a shared pointer that may be stored inside our container as it would prevent us to easily get rid of the object once not needed anymore ( the shared pointer inside the container would still participate to the object count ).

Shared pointer may get a custom deleter that will let us do some housekeeping for the container

So this is a weak pointer ( that do not participate to the object count ( or in some very small extent( weak count ) ) that is chosen for our container.

Here is some code ( forgive me I chose widget and not rectangle ):

Our class that must inherit from this curious class ( e.g see Scott Meyers new book Effective Modern C++ item 19 )

class widget:public std::enable_shared_from_this<widget>

alias ( ~ typedef )

using widget_weakptr_cont_t  = std::unordered_map<std::string,std::weak_ptr<widget>>;
using widget_smrtp_t       = std::shared_ptr<widget>;
using uuid_t               = boost::uuids::uuid;

The factory function

static widget_smrtp_t widget_factory(void);

The container

static widget_weakptr_cont_t widget_cont;

The constructor is private ( you may also prevent all the other form of copy or move construction to strengthen the rule )

private:
    widget();
    void self_emplace(void);
    const uuid_t uuid_tag;

The custom deleter for the shared pointers

auto widgetDeleter = [](widget* pw) {
std::cout << "Widget deleter" << std::endl;

widget::widget_cont.erase(pw->uuid_to_string());

delete pw;

if ( widget::widget_cont.empty() )
    std::cout << "No Widget left" << std::endl; };

The factory function

widget::widget_smrtp_t widget::widget_factory(void)
{
    auto wshp = widget_smrtp_t(new widget(),widgetDeleter);

    wshp->self_emplace();

    return wshp;

}

The self_emplace function

void widget::self_emplace(void)
{
    widget::widget_cont.emplace(uuid_to_string(),shared_from_this());
}

You may then use your factory function inside some other functions ( or main( ) )

auto pw = widget::widget_factory();

An example for retrieving our object from the container could be

for ( auto const & it : widget::widget_cont )
{
   //if interested by uuid we normally do
   // std::cout << it.first << std::endl;
   //For exercice we do the following:
   auto shp = it.second.lock();
   if ( shp )
   {
       std::cout << shp->uuid_to_string() << std::endl;
   }

}

In the execution below the function func ( not displayed here the post is already too long ) only makes a copy of a globally factored shared pointer (to one of our widget). The container is not modified by what happened inside func.

func2 creates another local widget that is destroyed when leaving func2. container is shown at these 2 steps.

Finally the globally constructed widget is only destroyed at the end (of the main )

Hello world!
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0

func
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0

func2
Widget elems are:
b2aedb78-8bb0-427e-9ada-fce37384f7de
84871b52-0757-44c1-be23-fb83e69468c0

Widget deleter
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0

bye !
Widget deleter
No Widget left

I hope all of this may help

NGI

EDIT 2016.08.21 I publish the "unabridged code" Code on Coliru It will not be much clearer because when I first replied I tried also other syntax features just for test.

Anyway you have now all in hands ( sometimes I do not publish a full code in order to avoid the "homework" copy/paste problem )

Lately I tried to simplify my code without success, 2 thoughts:

查看更多
登录 后发表回答