2016-12-22 2 views
4

Упрощенный надрез моего класса:Можете ли вы запретить вызов конструктора без создания экземпляра?

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--}; 
}; 

Это работает:

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

Это не:

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

... потому что вызываемый конструктор создает временный элемент, и деструктор немедленно запускается, оставляя систему «безопасной», когда ее не должно быть.

Легко совершить ошибку при написании второй, неисправной версии. Есть ли способ предотвратить такой вызов конструктора без создания экземпляра?

+0

Невозможно предотвратить это, нет. C++ позволяет анонимные временные файлы, вы ничего не можете с этим поделать. –

+1

Нет, класс не знает, что объект сохраняется в lvalue. –

+0

Я знаю, что я удалил его, мисс прочитала вопрос :) его рано еще с кофе :) – Rob

ответ

2

Есть ли способ предотвратить такой вызов конструктора без экземпляра?

Нет, вы не можете контролировать, как пользователи создают экземпляр класса.

Может быть, лучше имя будет поощрять правильное использование, что-то вроде:

class SystemUpdateGuard {..} 

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

Если вы явно хотите запретить вы могли бы временные переменные сделать некоторые хитрости.

Сделать конструктор UpdatingSystemprivate, создать заводской класс, который принимает только ссылку на unique_ptr<UpdatingSystem>. Таким образом, это требует Левое и из-за смарт-указатель объект будет уничтожен один раз из области видимости, что-то like:

#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; 
} 
+0

В качестве альтернативы вы можете просто использовать статическую функцию в классе 'UpdationSystem', который генерирует' unique_ptr'. Пример: static static_ptr UpdatingSystem :: Create() '. Сохраняет создание целого нового класса только для создания указателя :-) –

+0

Спасибо, Джилл, это похоже на то, что мне нужно. – user3775289

+0

Я тоже попробую ваше предложение Karl – user3775289

1

Как насчет охранника, как это:

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

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

Мне нравится этот подход. Это в основном обеспечивает то, что хочет OP, обертывая небезопасный код. –

0

Это архитектурный проблема.

К сожалению, единственным решением является изменение ваших небезопасных функций. Им должен потребоваться объект UpdatingSystem.

В конце концов ваш код должен выглядеть следующим образом ...

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

Это решает вашу проблему, сделав невозможным выполнение небезопасных операций без предварительного создания UpdatingSystem объекта.

Обновление небезопасных функций легко, просто передайте ему ссылку. Вам даже не нужно ничего делать с объектом или копировать его.

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

Такой подход обычно делает жизнь проще для программистов, а потому, что это единственный способ, чтобы заставить их правильно обрабатывать небезопасные функции.

Если «невозможно» определить безопасность на уровне функции таким образом, вам может потребоваться переосмыслить абстракции вашей программы.

Смежные вопросы