Reputation: 16630
I want my Timer objects to be created via Timer::create() only. For this purpose, I made the constructor private. However, I get a compiler error saying that "Timer::Timer(unsigned int)' is private" within the context of new_allocator.h. How can I solve this problem?
class Timer {
private:
int timeLeft;
Timer(unsigned int ms) : timeLeft(ms) {}
public:
static std::vector<Timer> instances;
static void create(unsigned int ms) {
instances.emplace_back(ms);
}
};
std::vector<Timer> Timer::instances;
Upvotes: 30
Views: 4695
Reputation: 473272
You can use transfer-of-friendship semantics to avoid having to have a specialized vector
allocator. It's a bit like dependency injection of friendship. This is really quite simple. You create an empty class who makes itself a friend of your class. But the default constructor is private, so only your class can create instances of it. But the class is still copyable, so it can be passed to anybody.
Your Timer
constructor will be public, but it requires one of these objects as an argument. Therefore, only your class, or a function called by it, can create these objects directly (copies/moves will still work).
Here's how you could do that in your code (live example):
class TimerFriend
{
public:
TimerFriend(const TimerFriend&) = default;
TimerFriend& operator =(const TimerFriend&) = default;
private:
TimerFriend() {}
friend class Timer;
}
class Timer {
private:
int timeLeft;
public:
Timer(unsigned int ms, const TimerFriend&) : timeLeft(ms) {}
static std::vector<Timer> instances;
static void create(unsigned int ms) {
instances.emplace_back(ms, TimerFriend());
}
};
std::vector<Timer> Timer::instances;
Upvotes: 17
Reputation: 12547
You probably should implement your own allocator, that will be friend to timer:
class Timer {
struct TimerAllocator: std::allocator<Timer>
{
template< class U, class... Args >
void construct( U* p, Args&&... args )
{
::new((void *)p) U(std::forward<Args>(args)...);
}
template< class U > struct rebind { typedef TimerAllocator other; };
};
friend class TimerAllocator;
private:
int timeLeft;
Timer(unsigned int ms) : timeLeft(ms)
{}
public:
static std::vector<Timer, TimerAllocator> instances;
static void create(unsigned int ms) {
instances.emplace_back(ms);
}
};
std::vector<Timer, Timer::TimerAllocator> Timer::instances;
int main()
{
Timer::create(100);
}
The simplest solution would be derive from std::allocator<Timer>
reimplementing rebind
to rebind to itself, so vector
couldn't rebind allocator back to std::allocator
and implement own construct
to actually create Timer
s.
Upvotes: 14