Dear people of stackoverflow.
I have a class, named FcgiManager, that is intended to handle a proper ammount of fastcgi workers.
Currently it has a simple method to add a new worker to list:
bool FcgiManager::AddWorker() {
workers_.push_back(std::make_unique<FcgiWorker>(server_));
return true;
}
The "workers_" field is:
private:
// cut
std::list<std::unique_ptr<FcgiWorker>> workers_;
The program exits with "bad weak pointer" exception.
When I trace it i see that from this method it does reache FcgiWorkes constructor, here it is:
FcgiWorker::FcgiWorker(std::shared_ptr<Dolly> server) :
running_{false}, pool_{std::make_unique<FcgiRequestPool>()}, server_{server} {
// actual code is not important, because execution doesn't get here.
}
And i see, that the "server" argument shared_ptr has some martian values in it's structure, like count = 1443278, weak = -1.
But in the AddWorker() method, just before entering FcgiWorker constructor the "server_" field has appropriate values.
I have even added an "IsAlive()" method to server and tried calling server_->IsAlive() from AddWorker() and yes, it's alive.
I also tried to plainly create a worker like this:
Any advice appreciated.
bool FcgiManager::AddWorker() {
FcgiWorker test(server_);
return true;
}
To check if I am doing something wrong with make_unique, but the result was the same.
Any advice appreciated.
Update-1:
FcgiWorker::server_ is:
std::shared_ptr<Dolly> server_;
it is initialized in the FcgiWorker constructor's initialization list, see constructor code above.
Update-2
FcgiManager::server_ is:
std::shared_ptr<Dolly> server_;
Here is how it is created in main.cpp:
auto server = std::make_shared<Dolly>();
server->BindFcgiManagerToServer();
server->Run();
server.cpp:
Dolly::Dolly() : start_time_{std::time(nullptr)} {
fcgi_manager_ = std::make_unique<FcgiManager>();
}
void Dolly::BindFcgiManagerToServer() {
fcgi_manager_->set_server(self());
}
server.h:
class Dolly : public std::enable_shared_from_this<Dolly> {
private:
// cut
inline std::shared_ptr<Dolly> self() { return shared_from_this(); }
Update-3 & Update-4 & 5
Created MCVE, and, oh well - it compiles and does not throw. So i guess i'll have to solve my problem myself now :)
Thanks everyone!
(MCVE updated twice, since it was not complete the first time)
#include <memory>
#include <list>
#include <iostream>
class Dolly;
class FcgiRequestPool {
};
class FcgiWorker {
public:
FcgiWorker(std::shared_ptr<Dolly> server) :
pool_{std::make_unique<FcgiRequestPool>()}, server_{server} {
std::cout << "worker created" << std::endl << std::flush;
}
private:
std::shared_ptr<FcgiRequestPool> pool_;
std::shared_ptr<Dolly> server_;
};
class FcgiManager {
public:
inline void set_server(std::shared_ptr<Dolly> server) { server_ = server; }
bool InitWorkers() {
auto workers_num = 4;
auto created_workers_num = 0;
try {
for (created_workers_num = 0; created_workers_num < workers_num; created_workers_num++) {
AddWorker();
}
} catch (std::exception& e) {
std::cout << e.what() << std::endl << std::flush;
}
return true;
}
void Run() {
InitWorkers();
}
private:
bool AddWorker() {
workers_.push_back(std::make_unique<FcgiWorker>(server_));
return true;
}
std::list<std::unique_ptr<FcgiWorker>> workers_;
std::shared_ptr<Dolly> server_;
};
class Dolly : public std::enable_shared_from_this<Dolly> {
public:
Dolly() {
fcgi_manager_ = std::make_unique<FcgiManager>();
}
void BindFcgiManagerToServer() {
fcgi_manager_->set_server(self());
}
void Run() {
fcgi_manager_->Run();
}
private:
std::unique_ptr<FcgiManager> fcgi_manager_;
std::shared_ptr<Dolly> self() {
return shared_from_this();
}
};
int main() {
auto server = std::make_shared<Dolly>();
server->BindFcgiManagerToServer();
server->Run();
return 0;
}
Resolved
After creating MCVE and comparing it step-by-step with the actual program, I found out, that the shared_ptr exception was generated here:
pool_{std::make_unique<FcgiRequestPool>()}
And has no relation to the whole classes creation logic.
I am marking the answer with MCVE advice as valid, because it is actually a great advice and it did help me.
The root cause: I was creating a unique_ptr to a class, which was derived from std::enable_shared_from_this.
Related
I am trying to create a DI container in C++ (for studying purposes). I know about boost DI container option, but I just want to have fun writing one by myself.
I would like that the created container only had one instance per object "registered", so I should apply the Singleton design pattern.
But, what would be the best (idiomatic) way to implement the Singleton Pattern as an in C++20 or, at least, in modern C++ and why?
Do you mean something like this, using meyer's singleton.
(https://www.modernescpp.com/index.php/thread-safe-initialization-of-a-singleton)
I never use singletons that need to be created with new, since their destructor never gets called. With this pattern the destructors do get called when the program terminates.
#include <iostream>
//-----------------------------------------------------------------------------
// create an abstract baseclass (closest thing C++ has to an interface)
struct data_itf
{
virtual int get_value1() const = 0;
virtual ~data_itf() = default;
protected:
data_itf() = default;
};
//-----------------------------------------------------------------------------
// two injectable instance types
struct test_data_container :
public data_itf
{
int get_value1() const override
{
return 0;
}
~test_data_container()
{
std::cout << "test_data_container deleted";
}
};
struct production_data_container :
public data_itf
{
int get_value1() const override
{
return 42;
}
~production_data_container()
{
std::cout << "production_data_container deleted";
}
};
//-----------------------------------------------------------------------------
// meyers threadsafe singleton to get to instances implementing
// interface to be injected.
//
data_itf& get_test_data()
{
static test_data_container test_data;
return test_data;
}
data_itf& get_production_data()
{
static production_data_container production_data;
return production_data;
}
//-----------------------------------------------------------------------------
// object that needs data
class my_object_t
{
public:
explicit my_object_t(const data_itf& data) :
m_data{ data }
{
}
~my_object_t()
{
std::cout << "my_object deleted";
}
void function()
{
std::cout << m_data.get_value1() << "\n";
}
private:
const data_itf& m_data;
};
//-----------------------------------------------------------------------------
int main()
{
auto& data = get_production_data();
my_object_t object{ data };
object.function();
return 0;
}
I am receiveing commands through json, which I insert in to a pipe. For this reason thye must have the same base class.
The pipe is read by a pipe handler, some commands are consumed by the pipe handler, others have to be passed down to a device, which is a member of the pipe handler. I could simply do this:
class Command{};
class HandlerCommand : public Command {
void execute(Handler* h);
};
class DeviceCommand : public Command {
void execute(Device* d);
};
Command* c = pipe.receive();
if (const auto hc = dynamic_cast<const HandlerCommand*>(c)) { hc.execute( **handlerptr** ); }
else if (const auto dc = dynamic_cast<const DeviceCommand*>(c)) { dc.execute( **deviceptr** );}
Device and pipehandler should not have the same base, since they have no common methods, fields, they are conceptually different.
Is there a way to avoid using dynamic cast here. I was thinking maybe there is some neat design pattern for this, but couldn`t quit come up with a better solution.
EDIT: did not derive DeviceCommand and HandlerCommand from command, fixed this.
You cannot use polymorphism of two things which have nothing in common. You will need the same base class/interface: in your case Command. As mentioned above your base class requires a pure virtual function that must be implemented by the derived classes. I will utilize a Command * clone()const prototype, which could be very useful later on. Please introduce a virtual destructor of your base class, otherwise, to track down this memory error could be a pain in the ass. Note, regarding your dynamic_cast the member function execute, must be const. You may try this:
#include <iostream>
#include <vector>
class Handler
{
public:
Handler(){}
};
class Device
{
public:
Device(){}
};
enum class CommandType{Handler,Devise};
class Command
{
public:
virtual ~Command(){}
virtual Command*clone()const = 0;
virtual CommandType getType()const = 0;
};
class HandlerCommand : public Command {
public:
HandlerCommand():Command(){}
void execute(Handler* h) const
{
std::cout << __FUNCTION__<<"\n";
}
HandlerCommand*clone()const { return new HandlerCommand(*this); }
CommandType getType()const { return CommandType::Handler; }
};
class DeviceCommand : public Command{
public:
DeviceCommand():Command(){}
void execute(Device* d)const
{
std::cout << __FUNCTION__<<"\n";
}
DeviceCommand*clone()const { return new DeviceCommand(*this); }
CommandType getType()const { return CommandType::Devise; }
};
int main()
{
Device dev;
Handler handler;
std::vector<Command*> pipe{ new HandlerCommand(), new DeviceCommand() };
while (!pipe.empty())
{
Command* c = pipe.back();
if (c->getType() == CommandType::Handler) { static_cast<const HandlerCommand*>(c)->execute(&handler); }
else if (c->getType() == CommandType::Devise ) { static_cast<const DeviceCommand*>(c)->execute(&dev); }
delete c;
pipe.pop_back();
}
std::cin.get();
}
outputs:
DeviceCommand::execute
HandlerCommand::execute
Version 2.0 using std::variant. You will need at least C++17 to compile this. Note, a single pipe container can exclusively comprise one of the mentioned classes within the variant. So there is no casting anymore, but you will need two pipes. Because of that, I introduced a time stamp variable.
#include <iostream>
#include <vector>
#include <variant>
class Handler
{
public:
Handler() {}
};
class Device
{
public:
Device() {}
};
class HandlerCommand {
int ts;
public:
HandlerCommand(int _ts):ts(_ts) {}
void execute(Handler* h) const
{
std::cout << ts << ": "<< __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
class DeviceCommand {
int ts;
public:
DeviceCommand(int _ts) :ts(_ts) {}
void execute(Device* d)const
{
std::cout << ts << ": " << __FUNCTION__ << "\n";
}
int timeStamp()const { return ts; }
};
using Command = std::variant<HandlerCommand, DeviceCommand>;
int main()
{
Device dev;
Handler handler;
std::vector<Command> hcPipe{HandlerCommand(2),HandlerCommand(5)};
std::vector<Command> dcPipe{DeviceCommand(1),DeviceCommand(4)};
Command single = DeviceCommand(0);
if (single.index() == 0)
{
std::get<HandlerCommand>(single).execute(&handler);
}
else
{
std::get<DeviceCommand>(single).execute(&dev);
}
while (!hcPipe.empty() || !dcPipe.empty())
{
if (!hcPipe.empty() && (dcPipe.empty() || std::get<HandlerCommand>(hcPipe.front()).timeStamp() < std::get<DeviceCommand>(dcPipe.front()).timeStamp()))
{
std::get<HandlerCommand>(hcPipe.front()).execute(&handler);
hcPipe.erase(hcPipe.begin());
}
else
{
std::get<DeviceCommand>(dcPipe.front()).execute(&dev);
dcPipe.erase(dcPipe.begin());
}
}
std::cin.get();
}
outputs:
0: DeviceCommand::execute
1: DeviceCommand::execute
2: HandlerCommand::execute
4: DeviceCommand::execute
5: HandlerCommand::execute
I have designed a simple callback-keyListener-"Interface" with the help of a pure virtual function. Also I used a shared_ptr, to express the ownership and to be sure, that the listener is always available in the handler. That works like a charme, but now I want to implement the same functionality with the help of std::function, because with std::function I am able to use lambdas/functors and I do not need to derive from some "interface"-classes.
I tried to implement the std::function-variant in the second example and it seems to work, but I have two questions related to example 2:
Why does this example still work, although the listener is out of scope? (It seems, that we are working with a copy of the listener instead of the origin listener?)
How can I modify the second example, to achieve the same functionality like in the first example (working on the origin listener)? (member-ptr to std::function seems not to work! How can we handle here the case, when the listener is going out of scope before the handler? )
Example 1: With a virtual function
#include <memory>
struct KeyListenerInterface
{
virtual ~KeyListenerInterface(){}
virtual void keyPressed(int k) = 0;
};
struct KeyListenerA : public KeyListenerInterface
{
void virtual keyPressed(int k) override {}
};
struct KeyHandler
{
std::shared_ptr<KeyListenerInterface> m_sptrkeyListener;
void registerKeyListener(std::shared_ptr<KeyListenerInterface> sptrkeyListener)
{
m_sptrkeyListener = sptrkeyListener;
}
void pressKey() { m_sptrkeyListener->keyPressed(42); }
};
int main()
{
KeyHandler oKeyHandler;
{
auto sptrKeyListener = std::make_shared<KeyListenerA>();
oKeyHandler.registerKeyListener(sptrKeyListener);
}
oKeyHandler.pressKey();
}
Example 2: With std::function
#include <functional>
#include <memory>
struct KeyListenerA
{
void operator()(int k) {}
};
struct KeyHandler
{
std::function<void(int)> m_funcKeyListener;
void registerKeyListener(const std::function<void(int)> &funcKeyListener)
{
m_funcKeyListener = funcKeyListener;
}
void pressKey() { m_funcKeyListener(42); }
};
int main()
{
KeyHandler oKeyHandler;
{
KeyListenerA keyListener;
oKeyHandler.registerKeyListener(keyListener);
}
oKeyHandler.pressKey();
}
std::function<Sig> implements value semantic callbacks.
This means it copies what you put into it.
In C++, things that can be copied or moved should, well, behave a lot like the original. The thing you are copying or moving can carry with it references or pointers to an extrenal resource, and everything should work fine.
How exactly to adapt to value semantics depends on what state you want in your KeyListener; in your case, there is no state, and copies of no state are all the same.
I'll assume we want to care about the state it stores:
struct KeyListenerA {
int* last_pressed = 0;
void operator()(int k) {if (last_pressed) *last_pressed = k;}
};
struct KeyHandler {
std::function<void(int)> m_funcKeyListener;
void registerKeyListener(std::function<void(int)> funcKeyListener) {
m_funcKeyListener = std::move(funcKeyListener);
}
void pressKey() { m_funcKeyListener(42); }
};
int main() {
KeyHandler oKeyHandler;
int last_pressed = -1;
{
KeyListenerA keyListener{&last_pressed};
oKeyHandler.registerKeyListener(keyListener);
}
oKeyHandler.pressKey();
std::cout << last_pressed << "\n"; // prints 42
}
or
{
oKeyHandler.registerKeyListener([&last_pressed](int k){last_pressed=k;});
}
here we store a reference or pointer to the state in the callable. This gets copied around, and when invoked the right action occurs.
The problem I have with listeners is the doulbe lifetime issue; a listener link is only valid as long as both the broadcaster and reciever exist.
To this end, I use something like this:
using token = std::shared_ptr<void>;
template<class...Message>
struct broadcaster {
using reciever = std::function< void(Message...) >;
token attach( reciever r ) {
return attach(std::make_shared<reciever>(std::move(r)));
}
token attach( std::shared_ptr<reciever> r ) {
auto l = lock();
targets.push_back(r);
return r;
}
void operator()( Message... msg ) {
decltype(targets) tmp;
{
// do a pass that filters out expired targets,
// so we don't leave zombie targets around forever.
auto l = lock();
targets.erase(
std::remove_if( begin(targets), end(targets),
[](auto&& ptr){ return ptr.expired(); }
),
end(targets)
);
tmp = targets; // copy the targets to a local array
}
for (auto&& wpf:tmp) {
auto spf = wpf.lock();
// If in another thread, someone makes the token invalid
// while it still exists, we can do an invalid call here:
if (spf) (*spf)(msg...);
// (There is no safe way around this issue; to fix it, you
// have to either restrict which threads invalidation occurs
// in, or use the shared_ptr `attach` and ensure that final
// destruction doesn't occur until shared ptr is actually
// destroyed. Aliasing constructor may help here.)
}
}
private:
std::mutex m;
auto lock() { return std::unique_lock<std::mutex>(m); }
std::vector< std::weak_ptr<reciever> > targets;
};
which converts your code to:
struct KeyHandler {
broadcaster<int> KeyPressed;
};
int main() {
KeyHandler oKeyHandler;
int last_pressed = -1;
token listen;
{
listen = oKeyHandler.KeyPressed.attach([&last_pressed](int k){last_pressed=k;});
}
oKeyHandler.KeyPressed(42);
std::cout << last_pressed << "\n"; // prints 42
listen = {}; // detach
oKeyHandler.KeyPressed(13);
std::cout << last_pressed << "\n"; // still prints 42
}
I have an object which contains a thread which indirectly accesses this object like so:
#include <iostream>
#include <thread>
#include <atomic>
class A;
class Manager
{
public:
Manager(void) = default;
void StartA(void)
{
a = std::make_unique<A>(*this);
}
void StopA(void)
{
a = nullptr;
}
A& GetA(void)
{
return *a;
}
private:
std::unique_ptr<A> a;
};
class A
{
public:
A(Manager& manager)
: manager{manager},
shouldwork{true},
thread{[&]{ this->Run(); }}
{
}
~A(void)
{
shouldwork = false;
thread.join();
}
private:
Manager& manager;
std::atomic<bool> shouldwork;
std::thread thread;
void Run(void)
{
while (shouldwork)
{
// Here goes a lot of code which calls manager.GetA().
auto& a = manager.GetA();
}
}
};
int main(int argc, char* argv[])
try
{
Manager man;
man.StartA();
man.StopA();
}
catch (std::exception& e)
{
std::cerr << "Exception caught: " << e.what() << '\n';
}
catch (...)
{
std::cerr << "Unknown exception.\n";
}
The problem is that when one thread calls Manager::StopA and enters destructor of A, the thread inside A segfaults at Manager::GetA. How can I fix this?
In StopA() you set a = nullptr;, this in turn destroys the a object and all further access to its members result in undefined behaviour (a likely cause the segmentation fault).
Simply moving the a = nullptr; to the destructor of the Manager could resolve this problem. Even better, allow the RAII mechanism of the std::unique_ptr to destroy the a object when the destructor of the Manager runs (i.e. remove the line of code completely).
With active object implementations, careful control of the member variables is important, especially the "stop variable/control" (here the shouldwork = false;). Allow the manager to access the variable directly or via a method to stop the active object before its destruction.
Some of the code here looks out of place or obscure, e.g. a = std::make_unique<A>(*this);. A redesign could help simplify some of the code. The Manager class could be removed.
class A
{
public:
A(): shouldwork{true}, thread{[&]{ this->Run(); }}
{
}
void StopA()
{
shouldwork = false;
thread.join();
}
private:
std::atomic<bool> shouldwork;
std::thread thread;
void Run(void)
{
while (shouldwork)
{
// code...
}
}
};
The code is modelled along the lines of std::thread, were the stopping of the tread is more controlled before an attempt is made to join it. The destructor is left empty in this case, to mimic the termination (calling std::terminate) result, as is the case with the standard thread library. Threads must be explicitly joined (or detached) before destruction.
Re-introducing the Manager, the code could look as follows;
class A
{
public:
A() : shouldwork{true}, thread{[&]{ this->Run(); }} {}
void StopA() { shouldwork = false; thread.join(); }
private:
void Run();
std::atomic<bool> shouldwork;
std::thread thread;
};
class Manager
{
public:
Manager() = default;
void StartA(void)
{
a = std::make_unique<A>();
}
void StopA(void)
{
a->StopA();
}
A& GetA(void)
{
return *a;
}
private:
std::unique_ptr<A> a;
};
void A::Run()
{
while (shouldwork)
{
// Here goes a lot of code which calls manager.GetA().
auto& a = manager.GetA();
}
}
And your main remains as it is.
I am having a hard time figuring how to design classes that can't initialize all their internal members in the constructor. I know that this should be something basic and discussed all over the net, but I'm not sure what to look for. So, for example, please consider the following code:
#include <iostream>
class Workhorse
{
public:
void SetData (const int &data)
{
this->data = data;
}
int GetData () const
{
return this->data;
}
private:
int data;
};
class Worker
{
public:
Worker ()
{
}
void Initialize (const int &data)
{
horse.SetData(data);
}
void Action () const
{
std::cout << horse.GetData() << std::endl;
}
private:
Workhorse horse;
};
int main ()
{
Worker worker;
worker.Initialize(3);
worker.Action();
return 0;
}
I want to prevent the workers from calling any methods without first calling Initialize(). The layman's implementation would be to add an isInitialized flag in the Worker class, set it to true in Initialize() and test it at the beginning of each public method (maybe also in the protected / private ones, if we introduce some inheritance?). Unfortunately, this seems a bit cumbersome and hard to maintain. Also, it's just awful to repeat an if statement in all methods. I haven't even began to ponder about thread safety issues, but, right now, I'm only implementing a single-threaded application. Is there a smarter way to design this?
EDIT: OK, I chose a dumb design as an example, which, indeed, is flawed. Let me try to give a clearer picture of what I have:
#include <iostream>
class PublicKeyCryptoProvider
{
public:
struct PublicKey
{
int shared;
};
struct PrivateKey
{
int secret;
};
int Encrypt (const int &plaintext) const
{
int ciphertext;
//apply encryption algorithm on plaintext
ciphertext = plaintext * this->pk.shared;
return ciphertext;
}
int Decrypt (const int &ciphertext) const
{
int plaintext;
//apply decryption algorithm on ciphertext
plaintext = ciphertext / this->sk.secret;
return plaintext;
}
void GenerateKeys ()
{
this->pk.shared = 4;
this->sk.secret = 4;
//generate pk and sk
}
void SetPublicKey (const PublicKey &pk)
{
this->pk = pk;
}
const PublicKey &GetPublicKey () const
{
return this->pk;
}
private:
PublicKey pk;
PrivateKey sk;
};
int main ()
{
/* scenario 1: */
PublicKeyCryptoProvider cryptoProvider;
cryptoProvider.GenerateKeys();
std::cout << cryptoProvider.Decrypt(cryptoProvider.Encrypt(3)) << std::endl;
/* /scenario 1: */
/* scenario 2: */
PublicKeyCryptoProvider cryptoProvider1;
cryptoProvider1.GenerateKeys();
PublicKeyCryptoProvider cryptoProvider2;
cryptoProvider2.SetPublicKey(cryptoProvider1.GetPublicKey());
int ciphertext = cryptoProvider2.Encrypt(3);
std::cout << cryptoProvider1.Decrypt(ciphertext) << std::endl;
//now let's do something bad...
std::cout << cryptoProvider2.Decrypt(ciphertext) << std::endl;
/* /scenario 2: */
return 0;
}
Obviously, you can imagine real life examples where scenario 2 is perfectly valid. Given the above situation, is there any better option than adding a canDecrypt flag inside the PublicKeyCryptoProvider class, which is set to true when generating keys and then tested at the beginning of the decrypt method? I have to mention that this is a very simple example, because, in my case, the PublicKeyCryptoProvider can perform faster encryptions if it is the owner of the secret key and it has much more public methods, so I would be doomed to test the flag more than a couple of times... Also, I have a client - server mockup scenario where the server exposes a bunch of public methods for the client, but the client can only call the methods after it has called the Initialize() method on the server...
I would do the following :
class Worker
{
public:
Worker (const int& data)
{
horse.SetData(data);
}
void Action () const
{
std::cout << horse.GetData() << std::endl;
}
private:
Workhorse horse;
};
Since you obviously don't want a Worker object to exist without being initialized, its initialization should be a part of its construction, and it should be instanciated without this initialization since it can't work without it.
It sounds like the behaviour you're interested in would entail having a class that acts as a manager, deciding whether to provide access to one of Workhorse's function, or a dummy function instead. One possibility would be to create an abstract parent class (Horse) specifying the interface of Workhorse, but not implementing any of the functions. Derive from it two classes, Workhorse, and TrojanHorse. TrojanHorse would implement all of the functions in the parent class as Shells, Workhorse would be as you've already created it.
The manager class could have the initialize function you're interested in, and it could store an object of type Horse. By default, the horse object could be assigned to a TrojanHorse object, but initialize would instead assign it to a Workhorse object.
This solution would avoid almost all of the speed impact from if statements, it would be maintainable in the sense that the compiler would give errors if the classes weren't changed in the proper manner, and it would still be comprehensible to another programmer looking at the code.
Great question! Its always good to make an API that is hard to use wrong, and as you are observing classes that are not fully constructed are dangerous, hard to use correctly and easy to use wrong. They set ourselves & others up for failure. I've done some refactoring on your second example to come up with a safer design that won't even allow your "do something bad" code.
The general idea was that PublicKeyCryptoProvider had too many responsibilities ( violation of SRP ):
Key generation
Key storage
Encryption
Decryption
Each one of the responsibilities has been delegated out. Now the PublicKeyCryptoProvider is more responsible for giving you the tools necessary to do encryption/decryption & key management.
#include <iostream>
#include <utility>
struct PublicKey
{
int shared;
};
struct PrivateKey
{
int secret;
};
struct KeyPair
{
PublicKey public_key;
PrivateKey private_key;
};
struct Encryptor
{
Encryptor( PublicKey shared_ )
: shared( shared_ )
{}
int Encrypt (const int &plaintext) const
{
int ciphertext;
//apply encryption algorithm on plaintext
ciphertext = plaintext * shared.shared;
return ciphertext;
}
private:
PublicKey shared;
};
struct Decryptor
{
Decryptor( PrivateKey secret_ )
: secret( secret_ )
{}
int Decrypt (const int &ciphertext) const
{
int plaintext;
//apply decryption algorithm on ciphertext
plaintext = ciphertext / secret.secret;
return plaintext;
}
private:
PrivateKey secret;
};
class PublicKeyCryptoProvider
{
public:
KeyPair GenerateKeys()
{
KeyPair keys;
//generate pk and sk
keys.public_key.shared = 4;
keys.private_key.secret = 4;
return keys;
}
Decryptor BuildDecryptor( PrivateKey key )
{
return Decryptor( key );
}
Encryptor BuildEncryptor( PublicKey key )
{
return Encryptor( key );
}
/* These are replaced by directly building an Encryptor/Decryptor
when you have a public or private key.
void SetPublicKey (const PublicKey &pk)
{
this->pk = pk;
}
const PublicKey &GetPublicKey () const
{
return this->pk;
}
*/
};
int main ()
{
/* scenario 1: */
PublicKeyCryptoProvider cryptoProvider;
auto keys = cryptoProvider.GenerateKeys();
auto decryptor = cryptoProvider.BuildDecryptor(keys.private_key);
auto encryptor = cryptoProvider.BuildEncryptor(keys.public_key);
std::cout << decryptor.Decrypt( encryptor.Encrypt(3) ) << std::endl;
/* /scenario 1: */
/* scenario 2: */
PublicKeyCryptoProvider cryptoProvider1;
auto keys1 = cryptoProvider1.GenerateKeys();
PublicKeyCryptoProvider cryptoProvider2;
auto encryptor2 = cryptoProvider2.BuildEncryptor(keys.public_key);
int ciphertext = encryptor2.Encrypt(3);
std::cout << decryptor.Decrypt(ciphertext) << std::endl;
// I Can't do anything bad - the API has protected me from doing bad things! Yeah!
//std::cout << cryptoProvider2.Decrypt(ciphertext) << std::endl;
/* /scenario 2: */
return 0;
}
You mentioned that you didn't think inheritance is the way to go, but there is a fairly clean way to do this with minimal inheritance.
A couple of design patterns are useful here. If you split the interface away from the implementation and think of the implementations as "always return an error" and "do something useful", you can view these two implementations as strategies and the interface as a proxy.
The proxy always forwards on it's calls to an implementation, and there is always an implementation (no need to check a flag).
The interface is initialized with a default implementation that causes an error of some kind (assert, throw, etc.). This is an example
Here's an example that I threw together that compiles with Clang 3.2:
#include <iostream>
#include <memory>
#include <cassert>
#include <stdexcept>
// Base class that defines the signatures of the functions to be forwarded.
// Another nice benefit is that each implementation can store whatever
// specific data they need.
class Impl {
public:
virtual void FuncA() = 0;
};
typedef std::unique_ptr<Impl> ImplPtr;
class ErrorImpl : public Impl {
public:
virtual void FuncA() {
assert(!"Don't call this before calling InitializeImpl!");
throw std::runtime_error("Don't call this before calling InitializeImpl!");
}
};
class OtherImpl : public Impl {
public:
void FuncA() {
std::cout << "Some other useful functionality here.\n";
}
};
// This is the class that user's will call.
class Proxy {
public:
Proxy() : impl_( ImplPtr(new ErrorImpl) ) {}
void InitializeImpl( ImplPtr ptr ) {
// You must std::move std::unique_ptr's.
impl_ = std::move( ptr );
}
void FuncA() { impl_->FuncA(); }
private:
ImplPtr impl_;
};
int main( int, char**) {
Proxy p;
// p.FuncA(); // asserts & throws.
p.InitializeImpl( ImplPtr(new OtherImpl) );
p.FuncA();
return 0;
}
If you must delay the object initialization, I would propose the usage of a proxy with an access operator throwing if the proxy is not initialized. Initialize the proxy whenever you want. You don't need an if check in each of your methods, but that check if moved to the proxy.
Some smart pointer would have been handy. But, as far as I know they don't throw if the containing pointer is uninitialized. So, you might need one of your own as given below.
#include <iostream>
class Workhorse
{
public:
void SetData (const int &data)
{
this->data = data;
}
int GetData () const
{
return this->data;
}
private:
int data;
};
template <typename T> class Proxy
{
public:
Proxy() : myObject(0)
{
}
Proxy(T* anObj) : myObject(anObj)
{
}
~Proxy()
{
delete myObject;
myObject = 0;
}
T* operator ->()const
{
if(NULL == myObject)
{
throw; // Bad object. Substitute an appropriate exception code.
}
return myObject;
}
private:
T* myObject;
};
class Worker
{
public:
Worker ()
{
}
~Worker ()
{
}
void Initialize (const int &data)
{
horse = new Workhorse;
horse->SetData(data);
}
void Action () const
{
// Here no need to check if the horse is initialized.
std::cout << horse->GetData() << std::endl;
}
private:
Proxy<Workhorse> horse;
};