c++ storing an object into an array of objects within the constructor of that object

前端 未结 2 1079
花落未央
花落未央 2020-12-22 03:14

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.

相关标签:
2条回答
  • 2020-12-22 03:39

    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:

    • class widget:public std::enable_shared_from_this < widget > { ... }; is already a CRTP
    • You can not use shared_from_this() when there is no shared_ptr < T > already existing SO: shared_from_this() causing bad_weak_ptr exception
    0 讨论(0)
  • 2020-12-22 03:52

    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.

    0 讨论(0)
提交回复
热议问题