Can you prevent constructor invocation without an instance?

Simplified snip of my class:

class UpdatingSystem
/* when system is "unsafe" it marks this condition by instantiating an
UpdatingSystem item. While this item exists errors are handled in a 
particular way. When the UpdatingSystem item goes out of scope error
handling reverts to normal.*/
{
private:
static THREAD int updatingSystemCount_;

public:
UpdatingSystem(const char* caller){updatingSystemCount++};
~UpdatingSystem(){updatingSystemCount--};
};

It works:

{
    UpdatingSystem tempUnsafe("Reason it unsafe");
    // do stuff that requires the system be 'unsafe' 
} // Revert to safe when destructor runs

It does not mean:

{
    UpdatingSystem("Reason it unsafe");
    // do stuff that requires the system be 'unsafe' 
} 

... because the called constructor creates a temporary element, and the destructor starts immediately, leaving the system "safe" when it should not be.

It is easy to make a mistake when writing a second, erroneous version. Is there a way to prevent such a constructor call without an instance?

+4
source share
4 answers

Is there any way to prevent such a constructor call without instantiation?

No, you cannot control how users create an instance of your class.

Perhaps a better name will contribute to proper use, for example:

class SystemUpdateGuard {..}

{
    SystemUpdateGuard guard_system_update("Reason it unsafe");
    // do stuff that requires the system be 'unsafe' 
} // Revert to safe when destructor runs
+2
source

, .

UpdatingSystem private, factory, unique_ptr<UpdatingSystem>. , lvalue, - , - :

#include <iostream>
#include <memory>

class UpdatingSystem
{
    friend class UpdatingSystemFactory;
    public:
    ~UpdatingSystem() { std::cout << "destructor UpdatingSystem"; }
    private:
    UpdatingSystem() { std::cout << "constructor UpdatingSystem";}
};

class UpdatingSystemFactory
{
    public:
    static void GenerateUpdatingSystem(std::unique_ptr<UpdatingSystem>& ptr)
    {
        ptr = std::unique_ptr<UpdatingSystem>(new UpdatingSystem());
    }
};

int main() 
{
    //..when having to create an updating system:
    {
      std::unique_ptr<UpdatingSystem> tmp;
      UpdatingSystemFactory::GenerateUpdatingSystem(tmp);
    }
    return 0;
}
+1

, :

...
UpdatingSystem(const char* caller, std::function<void()> func)
{
    updatingSystemCount++;
    f();
    updatingSystemCount--;
};
...

UpdatingSystem("whatever", [&](){ do_unsafe_stuff(); });
+1

.

, . UpdatingSystem.

:

{
    UpdatingSystem tempUnsafe("Reason it unsafe");
    unsafe_operation(tempUnsafe);
    safe_operation();
    another_unsafe_operation(tempUnsafe, 42);
} // Revert to safe when destructor runs

, UpdatingSystem.

Updating unsafe features is easy, just pass the link. You do not even need to do anything with the object or copy it.

another_unsafe_operation(UpdatingSystem const & lock, int data)
{
    // Do stuff, you don't even need to use the lock for anything.
}

This approach, as a rule, makes life easier for programmers, because this is the only way to get them to properly handle unsafe functions.

If it is “impossible” to define security at the function level this way, you may need to rethink the abstractions of your program.

0
source

Source: https://habr.com/ru/post/1664577/


All Articles