Preventing users from creating unnamed instances of a class [duplicate]

无人久伴 提交于 2019-11-30 17:17:17

The only sensible way I think about is to make the user pass the result of guard_creator::create to some guard_activator which takes a lvalue-reference as a parameter.

this way, the user of the class has no way but either create the object with a name (the sane option that most developers will do), or new it then dereference (insane options)

for example, you said in the comments you work on a non allocating asynchronous chain creator. I can think on an API which looks like this:

auto token = monad_creator().then([]{...}).then([]{...}).then([]{...}).create();
launch_async_monad(token); //gets token as Token&, the user has no way BUT create this object with a name 

If have access to the full potential of C++17, you can expand the idea of using a static factory function into something usefull: guarantied copy elision makes the static factory function possible even for non-movable classes, and the [[nodiscard]] attributes prompts the compiler to issue a warning if the return value is ignored.

class [[nodiscard]] Guard {
  public:
    Guard(Guard& other) = delete;
    ~Guard() { /* do sth. with _ptr */ }
    static Guard create(void* ptr) { return Guard(ptr); }
  private:
    Guard(void* ptr) : _ptr(ptr) {}
    void* _ptr;
};

int main(int, char**) {
  Guard::create(nullptr);
  //auto g = Guard::create(nullptr);
}

Compile in Compiler Explorer

You could use an extensible lint tool such as Vera++ https://bitbucket.org/verateam/vera/wiki/Home it lets you lint your code, you can create new rules using Python or tcl (I prefer Python)

A possible flow would be - after each commit, your CI system (e.g Jenkins) will run a job that executes Vera++ and validate such oversights, upon a failure a mail would be issued to the committer.

The canonical way to prevent a class from being instantiated is by making its constructor private. To actually get one of the desired instances, you call a static method, which returns a reference to a constructed object.

class Me {
public:
    static Me &MakeMe() { return Me(); }
private:
    Me();
}; // Me

This doesn't help of course - but it'd probably make the programmer pause!

int main() {
    Me(); // Invalid
    Me m; // Invalid
    Me::MakeMe(); // Valid - but who'd write that?
    Me m = Me::MakeMe();
} // main()

I know this isn't a direct analog to the Guard instances that you describe - but maybe you could adapt the concept?

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!