2013-06-09 34 views
17

Tôi muốn đối tượng Hẹn giờ của mình được tạo thông qua Timer :: create(). Với mục đích này, tôi đã tạo ra hàm tạo riêng. Tuy nhiên, tôi nhận được một lỗi trình biên dịch nói rằng "Timer :: Timer (unsigned int)" là riêng tư "trong bối cảnh của new_allocator.h. Làm thế nào tôi có thể giải quyết vấn đề này?vectơ :: emplace_back cho các đối tượng có hàm tạo riêng

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

Tất nhiên, lý do duy nhất tại sao 'push_back' sẽ làm việc là vì constructor sao chép/di chuyển là công khai. Nếu tất cả các hàm tạo là riêng tư, cả 'emplace_back' và' push_back' đều sẽ không hoạt động. – hvd

Trả lời

13

Bạn có lẽ nên thực hiện cấp phát của riêng bạn, đó sẽ là người bạn để hẹn giờ:

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

Giải pháp đơn giản nhất sẽ được lấy từ std::allocator<Timer> reimplementing rebind rebind cho chính nó, vì vậy vector không thể rebind cấp phát trở lại std::allocator và triển khai riêng construct để thực sự tạo Timer s.

+0

… hoặc bạn có thể tạo 'std :: vector ' một 'người bạn' trong lớp của bạn. Không hoàn toàn sạch sẽ nhưng đơn giản hơn nhiều. –

+6

@KonradRudolph, điều đó không đơn giản như vậy: Tất nhiên, tôi khuyên bạn nên làm cho người bạn vectơ, nếu nó hoạt động, nhưng điều đó là vector _does không gọi hàm tạo, phân bổ does_. Làm cho người bạn vectơ sẽ không giúp được gì. – Lol4t0

+0

Ah, đúng là tất nhiên rồi. Tôi chỉ đề nghị này trong một câu trả lời mà nó * làm việc * (với một 'std :: deque') nhưng bây giờ tôi không chắc chắn * tại sao * nó thực sự hoạt động. –

9

Bạn có thể sử dụng ngữ nghĩa chuyển giao của tình bạn để tránh phải có người chuyên phân bổ vector. Đó là một chút như tiêm phụ thuộc của tình bạn. Điều này thực sự khá đơn giản. Bạn tạo ra một lớp học trống rỗng, người tự biến mình thành một người bạn trong lớp của bạn. Nhưng hàm tạo mặc định là riêng tư, vì vậy chỉ có lớp của bạn mới có thể tạo ra các cá thể của nó. Nhưng lớp vẫn có thể sao chép được, vì vậy nó có thể được truyền cho bất kỳ ai.

Nhà xây dựng Timer của bạn sẽ được công khai, nhưng nó yêu cầu một trong các đối tượng này làm đối số. Do đó, chỉ có lớp của bạn, hoặc một hàm gọi là nó, có thể tạo trực tiếp các đối tượng này (bản sao/di chuyển sẽ vẫn hoạt động).

Đây là cách bạn có thể làm điều đó trong mã của bạn (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; 
Các vấn đề liên quan