2010-10-14 38 views
7

Giả sử tôi có một struct ++ C có cả POD và phi POD biến thành viên:Có cách nào để tạo giá trị cấu trúc C++-initialize tất cả các biến thành viên POD không?

struct Struct { 
    std::string String; 
    int Int; 
}; 

và để cho chương trình của tôi để tạo ra hành vi reproduceable Tôi muốn có tất cả các biến thành viên được khởi tạo ở xây dựng. Tôi có thể sử dụng một danh sách initializer cho rằng:

Struct::Struct() : Int() {} 

vấn đề là ngay sau khi tôi cần phải thay đổi cấu trúc của tôi và thêm một biến thành viên POD mới (nói bool Bool) Tôi có nguy cơ quên để thêm nó vào danh sách khởi tạo. Sau đó, biến thành viên mới sẽ không được khởi tạo giá trị trong khi xây dựng cấu trúc.

Ngoài ra tôi không thể sử dụng memset() lừa:

Struct::Struct() 
{ 
    memset(this, 0, sizeof(*this)); //can break non-POD member variables 
} 

vì gọi memset() ghi đè lên các biến thành viên POD phi đã xây dựng có thể phá vỡ những.

Có cách nào để thực thi khởi tạo giá trị của tất cả các biến thành viên POD mà không thêm rõ ràng quá trình khởi tạo trong trường hợp này không?

+0

Tôi muốn giới thiệu từng thành viên là 'const'. Đặc biệt là khi họ là tất cả 'công khai' nó thực sự có ý nghĩa để buộc bất biến. Bạn có thể sử dụng cú pháp khởi tạo mảng để tạo các cá thể: 'Struct s = {" ... ", 0};' –

+0

@Daniel: Và khi tôi muốn đặt nó vào một thùng chứa? – GManNickG

+0

@GMan: Tôi sẽ đặt nó trong một 'std :: shared_ptr' trong trường hợp này. Hoặc có thể quyết định đóng gói đúng các thành viên và xóa 'const'. –

Trả lời

10

Cách sạch sẽ để viết auto-initialzed lớp mẫu initialized<T>:

EDIT: Tôi nhận ra bây giờ nó có thể được thực hiện linh hoạt hơn bằng cách cho phép bạn khai báo initialized<Struct>. Điều này có nghĩa là bạn có thể khai báo khởi tạo mà không sửa đổi Struct gốc. Khởi tạo mặc định 'T()' được lấy cảm hứng từ câu trả lời Prasoons.

template<class T> 
struct initialized 
{ 
public: 

    initialized() 
     { value = T(); } 

    initialized(T t) 
     { value = t; } 

    initialized(const initialized<T>& x) 
     { value = x.value; } 

    T* operator &() { return &value; } 

    operator T&() { return value; }  

private: 
    T value; 
}; 


struct PodStruct 
{    
    std::string String;  
    int Int; 
}; 


struct GlorifiedPodStruct 
{    
    std::string String;  
    initialized<int> Int; 
}; 

void Test() 
{ 
    GlorifiedPodStruct s; 
    s.Int = 1; 
    int b = s.Int; 
    int * pointer = &s.Int; 

    initialized<PodStruct> s2; 
} 

Biên dịch này, nhưng có thể cần nhiều toán tử chuyển đổi, xử lý từ khóa dễ bay hơi, v.v. Nhưng bạn có ý tưởng.

+1

Hmmm. Có vẻ tốt, nhưng mục đích của 'value' là gì và sau đó cung cấp truy cập đầy đủ vào nó? Nó sẽ không được sạch hơn để chỉ công khai và loại bỏ các chuyển đổi? – sharptooth

+1

@sharptooth: Ý tưởng là bạn có thể sử dụng 'initialized ' gần giống như 'int'. Ví dụ: 'đã khởi tạo a; int b = a; 'công trình. Nếu không có toán tử chuyển đổi, bạn sẽ cần truy cập thành viên 'value' một cách rõ ràng. –

+1

@Martin B: Vâng, bạn nói đúng về việc truy cập trực tiếp, tôi không nghĩ về điều đó. Việc làm cho 'value' riêng tư không có ý nghĩa gì cả. – sharptooth

10

Liên Kết Câu hỏi here

Có cách nào để thực thi giá trị khởi tạo của tất cả các biến thành viên POD mà không cần thêm một cách rõ ràng khởi tạo của họ trong trường hợp này?

Tôi không chắc chắn liệu một cái gì đó như thế là có thể [trực tiếp] hay không nhưng sau việc

[email protected] ~ $ cat check.cpp && clang++ check.cpp && ./a.out 
#include <iostream> 
struct Struct { 
    std::string String; 
    int Int; 
    bool k; 
    // add add add 
}; 

struct InStruct:Struct 
{ 
    InStruct():Struct(){} 
}; 

int main() 
{ 
    InStruct i; 
    std::cout<< i.k << " " << i.Int << std::endl; 
} 
0 0 
[email protected] ~ $ 
+0

-1 Bạn chỉ may mắn và nhận được số không vì bộ nhớ mà 'i' được đặt vào đã xảy ra không được khởi tạo. Đây là _not_ được đảm bảo bởi tiêu chuẩn. –

+7

@Martin B: Tôi nghĩ rằng nó được đảm bảo bởi C++ 03. Xin vui lòng có một cái nhìn tại câu hỏi của tôi [ở đây] (http://stackoverflow.com/questions/3931312/value-initialization-and-non-pod-types) –

+4

Tôi đã học được điều gì đó - lời xin lỗi của tôi. Tôi đang loại bỏ các downvote và thêm một upvote. –

-1

Bạn có thể thêm một cấu trúc cơ sở:

struct PODStruct 
{ 
    PODStruct(unsinged int count) { memset(this, 0, count);} 
}; 

Và sau đó struct của bạn bắt nguồn từ cấu trúc cơ sở này, ngay từ đầu nếu bạn có nhiều hơn một cấu trúc cơ sở,

struct Struct : PODStruct 
{ 
    Struct(); 
    std::string Str; 
    int Int; 
} 

Struc::Struct() : PODStruct(sizeof(Struct)) 
{ 
} 
+2

Điều này dẫn đến UB. Bạn không thể 'memset' trên loại không phải POD, như' std :: string'. – GManNickG

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