Phân bổ bộ nhớ đối tượng tĩnh; intialize nó năng động?


9

Tôi có một đối tượng mà hàm tạo của nó được truyền tham số. Nếu tôi biết giá trị tham số tại thời gian biên dịch, tôi có thể xây dựng đối tượng tĩnh:

static FOOOBJ foo(3);

(Tôi hiểu rằng nó không thực sự được thực hiện tĩnh, tức là bởi trình biên dịch, nhưng thực sự được thực hiện trong quá trình thiết lập).

Nhưng nếu tôi không biết giá trị tham số khi biên dịch, tôi vẫn muốn phân bổ trước không gian cho đối tượng nhưng xây dựng đối tượng trong không gian đó vào thời gian chạy. Nó có thể được thực hiện mà không có một .initialize()phương pháp riêng biệt ?

Câu trả lời:


3

Sử dụng một initialize()phương thức cho một lớp là trái với nguyên tắc của một hàm tạo của lớp, tức là một khi một thể hiện của lớp đã được xây dựng , nó sẽ " sẵn sàng để sử dụng ".

Theo đề xuất của câu trả lời của Ignacio, cú pháp vị trí C ++ tốt hơn nhiều cho mục đích của bạn.

Tuy nhiên, với các thư viện Arduino, cú pháp vị trí không được hỗ trợ "ngoài luồng", do đó bạn phải tự thực hiện nó; đừng sợ, điều đó khá đơn giản:

void* operator new(size_t size, void* ptr)
{
    return ptr;
}

Cú pháp vị trí có thể là một con thú phức tạp trong C ++, nhưng với mục đích cụ thể của bạn, việc sử dụng nó có thể khá đơn giản:

static char buffer[sizeof FOOOBJ];
static FOOOBJ* foo;

void setup() {
    ...
    foo = new (buffer) FOOOBJ(3);
    ...
}

Sự khác biệt với mã hiện tại của bạn foolà bây giờ là một con trỏ, do đó, bất kỳ lệnh gọi phương thức nào cũng sẽ sử dụng ->thay vì ..

Nếu bạn hoàn toàn muốn tiếp tục sử dụng foonhư một ví dụ và không phải là một con trỏ, thì bạn có thể làm điều đó (nhưng tôi không khuyên nó như được giải thích sau) bằng cách sử dụng một tham chiếu thay thế:

static char buffer[sizeof FOOOBJ];
static FOOOBJ& foo = *((FOOOBJ*) buffer);

void setup() {
    ...
    new (buffer) FOOOBJ(3);
    ...
}

Vấn đề với mã này, là bạn không thể biết liệu foođã được xây dựng với một thể hiện thực FOOOBJhay chưa; bằng cách sử dụng một con trỏ, bạn luôn có thể kiểm tra xem nó có 0hay không.

Sử dụng cú pháp vị trí, bạn phải lưu ý rằng bạn không thể deletelấy fooví dụ ở trên. Nếu bạn muốn hủy foo(nghĩa là đảm bảo rằng hàm hủy của nó được gọi), thì bạn phải gọi hàm hủy một cách rõ ràng:

foo->~FOOOBJ();

1
Tôi đã không nhận thức được cú pháp nhưng điều đó hoàn toàn có ý nghĩa! Liệu các nhà xây dựng cần phải nhận thức / thiết kế cho nó? FOOOBJlà một đối tượng OneWire, sử dụng thư viện của Jim Studt (v2.2). Tôi nhận được tin nhắn error: no matching function for call to 'operator new(unsigned int, byte [14])'trong newcuộc gọi. Có vẻ như avr-g ++ có thể không hiểu cú pháp.
JRobert

Vâng, bạn đã đúng, tôi đang sử dụng Eclipse cho các dự án Arduino của tôi và những gì tôi đã kiểm tra nó, nó dường như hoạt động, ngoại trừ việc hoạt động là biên dịch Eclipse C ++, không phải avr-g ++! Tôi đã chỉnh sửa câu trả lời của mình để hiển thị một cách giải quyết đơn giản.
jfpoilpret

Về câu hỏi của bạn về nhà xây dựng, không có yêu cầu cụ thể, nhưng nếu chính nhà xây dựng thực hiện phân bổ động, thì vị trí mới sẽ không ngăn chặn được.
jfpoilpret

Tôi cũng đang sử dụng Eclipse - trình biên dịch C ++ nào được cấu hình của bạn? Ngoài ra, nhìn vào công cụ xây dựng OneWire, nó không có newgì, nó chỉ khởi tạo một số i / o.
JRobert

Tôi đang sử dụng Eclipse với plugin eclipse.baeyens.it (sử dụng các công cụ Arduino IDE, tức là avr-g ++ + Arduino libs); nhưng quá trình biên dịch C ++ xảy ra nhanh chóng với Eclipse C ++ và chỉ sử dụng avr-g ++ khi khởi chạy bản dựng Arduino. Tôi đã không kiểm tra bước sau ban đầu.
jfpoilpret

4

Bạn có thể sử dụng cú pháp vị trí để chỉ định phân bổ hiện có để khởi tạo lớp.

FOOOBJ foo(0);

 ...

  FOOOBJ *f = new (foo) FOOOBJ(3);

Tôi đề nghị thay thế khai báo foobằng char foo[sizeof FOOOBJ];để hàm FOOOBJtạo không được gọi foomà có thể là một vấn đề thực sự tùy thuộc vào những gì hàm tạo.
jfpoilpret
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.