0

How to self-document a function that use a custom allocator - to remind that its user must not cache the returned result.

I have a library and a user class, they use in-house polymorphic allocator.

  • Library : uses one-frame-allocator to generate return result of Library:fLib .
    The returned result will be invalid at the end of time-step.
  • User : want to cache the return result of Library:fLib to use in later frame.
    It is a bad design ; hence it needs some warning.

Here is the snippet. (full demo).

class Library{
    public: 
    OneFrameAllocator allo_;
    public: Report fLib(){   //<-- may need some semantic documentation
        Report report;
        report.setAllocator(&allo_);
        return report;
    }
};
Library lib;
class User{
    Report tmpCache;
    public: void fUser(){
        Report arr=lib.fLib();   //<-- still OK (should not warn)
        tmpCache=arr;            //<-- wrong usage, but hard to detect
    }

};
int main(){
    User user;
    user.fUser();
    lib.allo_.clearOneFrame();
    //HERE: user.tmpCache become dangling pointer internally (danger)
    return 0;
}

Question

How to warn coder of User not to cache return result of Library::fLib() semantically
(i.e. more than just comment /**/)?

I am considering to use smart pointer, but I don't think it can help because memory become invalidated from custom allocator, not from deleting a unique_ptr.

In real life, Library can also be a custom Array (that acts similar as std::vector).
In such case, the danger less obvious - "User try to copy Array" doesn't seem to be dangerous.

Sorry if the question is too newbie, I am very new to custom allocators.

Edit:
After looking into the rule of three. (thank paddy)
I believe the core of my problem can be depicted as :-

(pseudo code)
class Lib{
    OneFrameAllocator allo;
    public: std::unique_ptr<int> make_unique(){
        return allo.make_unique<int>(); 
        //^ memory will be invalidated when call "allo.clearOneFrame()"
    }
    public: void update(){
        allo.clearOneFrame();
    }
};
Library lib;
class User{
    std::unique_ptr<int> cache=nullptr;
    public: void fUser(){
        //do something about "cache"  <--- crash expected at 2nd frame
        std::unique_ptr<int> temp=lib.make_unique(); //<-- still OK
        cache=std::move(temp);            //<-- danger
    }
};
int main(){
    User user; 
    //--- 1st frame ----
    user.fUser();
    lib.update();
    //--- 2nd frame ----
    user.fUser();  //<--- crash expected
    lib.update();
}

I believe the problem is :
The class that has ownership (User) is not the class that controls memory allocation (Library).

It is not a good design, so I want to find a way to warn the coder of User that something is wrong by using C++ syntax/semantic-clue.

cppBeginner
  • 1,114
  • 9
  • 27
  • 1
    This is more an issue of not following the [Rule of Three](https://stackoverflow.com/q/4172722/1553090). You get a dangling pointer because you allowed copy semantics that did not create a true copy. Either delete the copy constructor and assignment operator (which will give you a compile error if you try to cache the value), or implement them properly (which will copy it properly, potentially via another custom allocator). – paddy Jun 09 '17 at 02:27
  • @paddy Should I create a custom copy function that has allocator as parameter? I have to sacrifice convenience of default copy constructor and copy assignment. (?) – cppBeginner Jun 09 '17 at 02:30
  • Maybe you should look at how the C++ standard library handles custom allocators. It's not quite the same as how you're doing it. Anyway, the moment you have non-trivial memory semantics, you need to have non-trivial constructor/destructor. You may also need to correctly handle move semantics (C++11 and above). The _convenience_ you speak of is actually laziness. Your usage pattern is a bit strange, as you have exposed your allocator publicly and talk about invalidating memory owned by another object. That breaks encapsulation. Maybe this is an [XY problem](http://xyproblem.info/). – paddy Jun 09 '17 at 02:37
  • @paddy Thank for useful comments. I found that standard library use allocator as [a template parameter](http://en.cppreference.com/w/cpp/container/vector) (I don't like), and polymorphism allocator is still an experimental feature (thus, it is so hard to find an example show extensive usage, best I found = https://stackoverflow.com/questions/38010544/polymorphic-allocator-when-and-why-should-i-use-it). ... To avoid XY problem (or to make it easier to point out whether it is), I have edited question to depict the problem in a somehow different way. I would be glad if you may take a look. – cppBeginner Jun 09 '17 at 06:50

0 Answers0