2010-02-08 37 views
33

Tôi muốn phân bổ một cấu trúc trên heap, khởi tạo nó và trả về một con trỏ đến nó từ một hàm. Tôi tự hỏi nếu có một cách cho tôi để khởi tạo các thành viên const của một struct trong kịch bản này:Làm thế nào để khởi tạo const thành viên của cấu trúc trên heap

#include <stdlib.h> 

typedef struct { 
    const int x; 
    const int y; 
} ImmutablePoint; 

ImmutablePoint * make_immutable_point(int x, int y) 
{ 
    ImmutablePoint *p = (ImmutablePoint *)malloc(sizeof(ImmutablePoint)); 
    if (p == NULL) abort(); 
    // How to initialize members x and y? 
    return p; 
} 

Tôi có nên kết luận từ này rằng không thể để phân bổ và khởi tạo một struct trên heap, trong đó có các thành viên const ?

Trả lời

48

Giống như vậy:

ImmutablePoint *make_immutable_point(int x, int y) 
{ 
    ImmutablePoint init = { .x = x, .y = y }; 
    ImmutablePoint *p = malloc(sizeof *p); 

    if (p == NULL) abort(); 
    memcpy(p, &init, sizeof *p); 

    return p; 
} 

(Lưu ý rằng không giống như C++, không có nhu cầu để cast giá trị trả về của malloc trong C, và nó thường được coi là hình thức xấu bởi vì nó có thể ẩn các lỗi khác).

+6

Lưu ý rằng việc sử dụng .x và .y trong khởi tạo init là C99, bạn tất nhiên có thể sử dụng các mục không được đặt tên nếu trình biên dịch của bạn không hỗ trợ. – Trent

+0

Brilliant, caf - cảm ơn bạn! – user268344

+4

+1 Để làm rõ về 'malloc' giữa C và C++. –

10

Nếu đây là C chứ không phải C++, tôi không thấy giải pháp nào khác ngoài việc loại bỏ hệ thống kiểu.

ImmutablePoint * make_immutable_point(int x, int y) 
{ 
    ImmutablePoint *p = malloc(sizeof(ImmutablePoint)); 
    if (p == NULL) abort(); 

    // this 
    ImmutablePoint temp = {x, y}; 
    memcpy(p, &temp, sizeof(temp)); 

    // or this 
    *(int*)&p->x = x; 
    *(int*)&p->y = y; 

    return p; 
} 
+1

Nếu đây là C, việc truyền giá trị trả về của 'malloc' là không cần thiết và dư thừa. – dreamlax

+1

@dreamlax: bắt tốt. Tôi thực sự nhớ điều đó về C

2

Nếu bạn khăng khăng giữ const trong cấu trúc, bạn sẽ phải làm một số đúc để có được xung quanh rằng:

int *cheat_x = (int *)&p->x; 
*cheat_x = 3; 
+2

Điều đó không gọi hành vi không xác định? – dreamlax

+2

Nếu bạn phân bổ bộ nhớ, tôi nghĩ rằng nó là tốt. – NateS

0

Tôi thích caf's approach, nhưng điều này xảy ra với tôi quá

ImmutablePoint* newImmutablePoint(int x, int y){ 
    struct unconstpoint { 
     int x; 
     int y; 
    } *p = malloc(sizeof(struct unconstpoint)); 
    if (p) { // guard against malloc failure 
     *p.x = x; 
     *p.y = y; 
    } 
    return (ImmutablePoint*)p; 
} 
+0

Xin lỗi, tôi không thấy const ở đây. Bạn có thể giải thích dùm không? – kevinarpe

+1

@KCArpe: Tôi phân bổ và gán một 'struct' giống hệt cấu trúc cho' ImmutablePoint' nhưng có thể thay đổi, sau đó bỏ con trỏ trong câu lệnh return để phiên bản có thể thay đổi không bao giờ được hiển thị cho người dùng.Đó là một sự lạm dụng khá tiêu chuẩn của việc đúc để "phá vỡ" hệ thống kiểu. Điểm bất lợi của giải pháp tương đối của quán cà phê này là nó không phải là [DRY] (http://en.wikipedia.org/wiki/Don%27t%5Frepeat%5Fyourself): nếu ai đó chỉnh sửa 'ImmutablePoint' tôi cần chỉnh sửa' unconstpoint' cũng. – dmckee

+3

điều này vi phạm nghiêm ngặt con trỏ-răng cưa. –

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