2014-09-25 15 views
5

Bối cảnh: Tôi đang ở trong một môi trường mã lớn, nơi thứ tự không xác định trong đó các nhà xây dựng toàn cầu đang chạy là có vấn đề. Vì vậy, tôi có một lớp tùy chỉnh được thiết kế để trì hoãn khởi tạo cho đến khi sử dụng lần đầu tiên. Tất cả phép thuật của nó xảy ra bên trong toán tử * và toán tử-> hàm; chúng là thứ duy nhất được xác định. Nó cũng lưu trữ một số trạng thái trong chính nó, để có sẵn cho chức năng khởi tạo tự động. Tất nhiên, trạng thái đó là POD, để toàn bộ lớp là POD, để nó có thể được thiết lập hoàn toàn trước khi mã của mọi người bắt đầu chạy, để mọi mã ở mọi nơi đều có thể sử dụng tất cả các hình cầu ở mọi nơi, mà không sợ chưa được thiết lập.C++ 11: Một toán tử gán có ngăn chặn một loại khỏi POD và do đó được khởi tạo toàn cục không?

Một thời gian trở lại một người nào đó đã thêm một toán tử gán riêng, không bao giờ được xác định, để loại đó sẽ không bao giờ được gán cho (nó chưa được thiết kế để thay đổi bao giờ). Bây giờ một người khác nói rằng lớp học bị phá vỡ vì nó không phải là POD. Nếu thay vì nó được khai báo nhưng không được xác định, tôi tuyên bố nó là "= xóa", tôi nghĩ rằng đó là bằng cách nào đó tốt hơn. Và thực sự, với thay đổi đó, tiêu chuẩn :: is_pod <> :: giá trị trả về đúng cho loại.

Nhưng liệu toán tử gán có ngăn chặn loại khỏi POD không? Tôi nghĩ rằng các yêu cầu chỉ là nó phải chỉ có các thành viên dữ liệu công khai, không có các phương thức ảo, và không có hàm tạo hoặc hàm hủy.

Và nhiều hơn nữa cho vấn đề của tôi: sự hiện diện của một toán tử gán không được định nghĩa có ngăn không cho khởi tạo lớp tại thời gian khởi tạo toàn cục, cùng với tất cả các POD toàn cầu khác không?

Giảm dụ:

struct LazyString { 
    const char *c_str; 

    bool has_been_inited; 
    string *lazy_str_do_not_use_directly; 

    string &operator*() { return *get(); } 
    string *operator->() { return get(); } 

private: 
    string *get() { 
    // The real code uses a mutex, of course, to be thread-safe. 
    if (!has_been_inited) { 
     lazy_str_do_not_use_directly = new string(c_str); 
     has_been_inited = true; 
    } 
    return lazy_str_do_not_use_directly; 
    } 

    // Does this make the class non-POD? 
    // If so, does that mean that global variables of this type 
    // will not be initialized at global-initialization time, that wonderful 
    // moment in time where no code has yet been run? 
    void operator=(const LazyString&); 

    // If I do this instead, it breaks C++03 compatibility, but is this somehow better? 
    void operator=(const LazyString&) = delete; 
}; 

LazyString lazy = { "lazy" }; 

int main(int argc, char *argv[]) { 
    std::cout << *lazy; 
} 
+0

Pha chế quản lý bộ nhớ heap của riêng bạn gần như không bao giờ là ý tưởng hay. Tại sao bạn nghĩ rằng bạn cần điều này? (Ý bạn là thực hiện s.th. tương tự như [copy-on-write] (http://stackoverflow.com/questions/12199710/legality-of-cow-stdstring-implementation-in-c11)) –

+1

Bạn là gây nhầm lẫn POD-Ness và khởi tạo tĩnh. Không phụ thuộc vào nhau. –

+0

Vì tất cả các thành viên dữ liệu đều hiển thị công khai, khai báo đó tạo nên POD, có. ** LƯU Ý: ** Bạn sẽ gặp phải các tác dụng phụ không mong muốn liên quan đến 'chuỗi mới (c_str);' trong khởi tạo _lazy của bạn, khi sao chép/gán kiểu POD này xung quanh. –

Trả lời

6

Liệu một toán tử gán ngăn chặn một loại từ là POD

Yes. Loại POD phải là tầm thường; và phải là có thể sao chép một cách trivially; và vì vậy phải không có bản sao không tầm thường hoặc di chuyển các toán tử gán.

Bất kỳ toán tử nào do người dùng cung cấp đều không nhỏ, do đó việc khai báo hàm tạo bản sao làm cho lớp không tầm thường và do đó không phải POD.

và do đó được khởi tạo toàn cầu?

Không. Bất kỳ loại khả thi nào, POD hay không, đều có thể là biến toàn cầu.

CẬP NHẬT: Từ những nhận xét, bạn có nghĩa là để hỏi:

nó có thể là tĩnh, chứ không phải là tự động, khởi tạo?

Có, vì nó có một hàm tạo tầm thường; miễn là trình khởi tạo là một biểu thức không đổi. Trong ví dụ của bạn, { "lazy" } là một biểu thức không đổi, vì vậy LazyString có thể được khởi tạo tĩnh.

Tính năng quan trọng ở đây là nó có một hàm tạo tầm thường, không phải là POD. POD nghĩa là nó cũng đáp ứng các yêu cầu khác nhau, không liên quan đến việc khởi tạo.

+0

Tôi tin rằng câu đúng là "Bất kỳ người dùng nào ** được cung cấp ** điều hành là không tầm thường". Ví dụ, 'class foo {foo & operator = (foo const &) = mặc định; }; 'có một toán tử gán bản sao do người dùng khai báo tầm thường. –

+0

@CassioNeri: Cảm ơn bạn đã sửa. Thật dễ dàng để mất dấu vết của những sắc thái của ý nghĩa. –

+0

Bạn đã nói "Bất kỳ loại tức thì nào, có thể là biến toàn cục" và trong khi đúng, điều đó không trả lời được câu hỏi của tôi. Ví dụ, nếu tôi có foo1.cc, chứa khởi tạo toàn cục "int foo = printf (" Hello World \ n ");", và cũng foo2.cc, có chứa khởi tạo toàn cầu "extern int foo; int bar = foo;", sau đó tôi không thể biết, theo tiêu chuẩn C++, thanh giá trị nào sẽ kết thúc với, vì cả hai đều là khởi tạo động. Đó là lý do tại sao tôi đang cố gắng để loại bỏ bất kỳ và tất cả các khởi tạo năng động ... nhưng tôi không biết nếu thực tế là tôi chỉ định tất cả các lĩnh vực của cấu trúc này với PODs là đủ. – jorgbrown

2

C++ có một số giai đoạn khởi tạo cho các biến không phải cục bộ với thời gian lưu trữ tĩnh (biến toàn cầu thuộc danh mục này) - bất kể loại đó có phải là POD hay không.

  • zero khởi diễn ra trước khi bất kỳ khởi khác
  • khởi liên tục diễn ra
  • khởi động

Hai loại đầu tiên khởi tạo phải diễn ra trước khi khởi động. Khởi động động là tình huống mà thứ tự khởi tạo có thể khó thiết lập. Một số khởi tạo động không theo thứ tự, một số được sắp xếp trong một đơn vị dịch, v.v.

Thậm chí nếu biến toàn cầu không phải là POD, bạn có thể chắc chắn rằng việc khởi tạo zero sẽ diễn ra trước bất kỳ init động nào.

Xem C++ 11 3.6.2 "Khởi tạo biến không phải cục bộ" để biết chi tiết.

+0

Như tôi đã hiểu, khởi tạo động có thể tham khảo các hình ảnh từ các tệp khác. Là tác giả của một tệp khác, tôi muốn chắc chắn rằng các hình ảnh của tôi có sẵn cho tất cả các vars khởi tạo động. Đó là, tôi muốn chắc chắn rằng lớp của tôi được khởi tạo ở thời gian khởi tạo không đổi. Tôi biết rằng nếu lớp của tôi là POD, hoặc tuyên bố constexpr, rằng nó sẽ được đảm bảo để được khởi tạo trong giai đoạn "khởi tạo liên tục". Nhưng lớp LazyString của tôi có được đảm bảo chạy trước init động không? – jorgbrown

+0

Khởi tạo tĩnh diễn ra trước bất kỳ khởi tạo động nào trong chương trình. Vì vậy, đối tượng toàn cục 'LazyString' của bạn được khởi tạo trước khi bất kỳ khởi tạo động nào của đối tượng khác có thể gọi' LazyString :: get() '. –

Các vấn đề liên quan