2013-06-09 13 views
17

Chcę, aby moje obiekty Timer były tworzone tylko przez Timer :: create(). W tym celu uczyniłem konstruktora prywatnym. Dostaję jednak błąd kompilatora mówiąc, że "Timer :: Timer (unsigned int)" jest prywatny "w kontekście new_allocator.h. Jak mogę rozwiązać ten problem?vector :: emplace_back dla obiektów z prywatnym konstruktorem

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; 
+1

Oczywiście, to jedyny powód dlaczego 'push_back' będzie działać tak, ponieważ konstruktor kopia/ruch jest publiczna. Jeśli wszystkie konstruktory są prywatne, ani 'emplace_back' ani' push_back' nie będą działać. – hvd

Odpowiedz

13

Prawdopodobnie powinien realizować swoją przydzielania, który będzie przyjacielem czasowy:

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

Najprostszym rozwiązaniem byłoby czerpać z std::allocator<Timer> reimplementing rebind ponownie powiązać do siebie, więc nie mogła ponownie powiązać vector alokator z powrotem do std::allocator i zaimplementuj własne construct, aby faktycznie utworzyć Timer s.

+0

... lub możesz uczynić 'std :: vector ' 'przyjacielem 'twojej klasy. Nie tak czysty, ale znacznie prostszy. –

+6

@KonradRudolph, to nie takie proste: Oczywiście, poradziłbym się, żeby zrobić wektorowego przyjaciela, jeśli to działa, ale chodzi o to, że wektor _ nie wywołuje konstruktora, alokator robi_. Tworzenie znajomego wektorowego nie pomoże. – Lol4t0

+0

Ach, oczywiście. Właśnie poleciłem to w innej odpowiedzi, gdzie to * działało * (z 'std :: deque'), ale teraz nie jestem pewien * dlaczego * to faktycznie działa. –

9

Można użyć semantyki przeniesienia przyjaźni, aby uniknąć konieczności posiadania wyspecjalizowanej alokacji vector. To trochę jak zastrzyk przyjaźni. To naprawdę bardzo proste. Tworzysz pustą klasę, która staje się przyjacielem twojej klasy. Ale domyślny konstruktor jest prywatny, więc tylko twoja klasa może tworzyć jego instancje. Ale klasa jest nadal kopiowalna, więc można ją przekazać każdemu.

Twój konstruktor Timer będzie publiczny, ale wymaga jednego z tych obiektów jako argumentu. Dlatego tylko twoja klasa lub funkcja przez nią wywoływana może tworzyć te obiekty bezpośrednio (kopie/ruchy będą nadal działać).

Oto jak można to zrobić w kodzie (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; 
Powiązane problemy