Take 2
I think I've incorporated all the comments. If I missed something please remind me below.
I changed the Fan class to use std::unique_ptr too and added some code to the skeleton. But let me mention again that it's just a sekelton for some Resource that needs to be moved into Inproc. It doesn't do anything as is.
I changed NULL to nullptr and set the copy constructor/assignment to delete since copying the resources is not allowed. I also added some comment and added debug output and a main() function so you can run it and see what goes on. The first example would compile but couldn't be run.
I couldn't get std::make_unique to work since the constructor is private.
I changed *__ to *init to avoid the reserved namespace. I can't use plain peer since that would shadow the peer() function. So member variables are * and initializers are *_init across the board.
#include <memory>
#include <iostream>
#include <cassert>
#define START std::cout << __PRETTY_FUNCTION__ << std::endl
#define END std::cout << __PRETTY_FUNCTION__ << " done" << std::endl
class Fan {
public:
// Factory with dependency inversion, creates all resource before calling
// the constructor
static std::unique_ptr<Fan> create(Fan *peer_init = nullptr) {
START;
// some resource allocations left out for simplicity
// epoll file descriptor
// read and write ready and blocked queues
// if they fail create returns nullptr
// error: 'Fan::Fan(Fan*)' is private
// std::unique_ptr<Fan> fan = std::make_unique<Fan>(peer_init);
std::unique_ptr<Fan> fan(new(std::nothrow) Fan(peer_init));
END;
return fan;
}
~Fan() {
START;
std::cout << " this = " << this << " peer = " << peer_ << std::endl;
if (peer_) peer(nullptr);
END;
}
private:
// no copying
Fan(const Fan &) = delete;
Fan & operator =(const Fan &) = delete;
// set/reset peer_ pointer
void peer(Fan *peer_init) {
START;
std::cout << " before: this = " << this << " peer = " << peer_ << std::endl;
if (peer_init) { // finish linking peers
assert(!peer_); // must not have an observer
assert(peer_init->peer_ == this); // must already be observed by peer
peer_ = peer_init;
} else { // break peers apart
assert(peer_); // must have an observer
assert(peer_->peer_ == this); // must be observed by peer
peer_->peer_ = nullptr;
peer_ = nullptr;
}
std::cout << " after: this = " << this << " peer = " << peer_ << std::endl;
END;
}
// constructor connects to other peer if given
// other resources left out for simplicity
Fan(Fan * peer_init /*, resource, resource */) : peer_(peer_init) {
START;
if (peer_) {
assert(!peer_->peer_);
peer_->peer(this);
}
END;
};
Fan *peer_; // peer on the other side
};
class Inproc {
public:
// Factory with dependency inversion, creates all resource before calling
// the constructor
static std::unique_ptr<Inproc> create() {
START;
// create first Fan of a pair
if (auto bound = Fan::create()) {
// create second Fan connected to the first
if (auto connected = Fan::create(bound.get())) {
// create Inproc with all resource pre-allocated
/* error: 'Inproc::Inproc(std::unique_ptr<Fan>,
std::unique_ptr<Fan>)' is private
std::unique_ptr<Inproc> inproc =
std::make_unique<Inproc>(std::move(bound),
std::move(connected));
*/
std::unique_ptr<Inproc> inproc(
new(std::nothrow) Inproc(std::move(bound),
std::move(connected)));
// verify that ownership has moved on
std::cout << " bound is now: " << bound.get() << std::endl;
END;
return inproc;
}
}
END;
return std::unique_ptr<Inproc>(nullptr);
}
~Inproc() {
START;
// nothing to do now anymore
END;
}
private:
// constructor takes over ownership of resources
Inproc(std::unique_ptr<Fan> bound__, std::unique_ptr<Fan> connected__)
: bound_(std::move(bound__)), connected_(std::move(connected__)) {
START;
// other stuff left out for simplicity
END;
}
// no copying
Inproc(const Inproc &) = delete;
Inproc & operator =(const Inproc &) = delete;
// resources
std::unique_ptr<Fan> bound_;
std::unique_ptr<Fan> connected_;
};
// test
int main() {
std::unique_ptr<Inproc> inproc = Inproc::create();
std::cout << __PRETTY_FUNCTION__ << ": cleaning up" << std::endl;
inproc.reset();
}