Đó thực sự là một câu hỏi thú vị. Trước hết, lưu ý rằng chúng ta đang ở một ngôn ngữ bắt buộc, có nghĩa là khi bạn yêu cầu một thứ gì đó (thậm chí vô ích, chẳng hạn như xây dựng một đối tượng không sử dụng) thì trình biên dịch cần tuân thủ trừ khi nó có thể xuất hiện với một biểu mẫu tương đương. . Về cơ bản, nó có thể bỏ qua các tham số nếu nó có thể chứng minh rằng làm như vậy sẽ không thay đổi ý nghĩa của chương trình.
Khi bạn viết một lời gọi hàm, có hai điều có thể xảy ra (cuối cùng):
- hoặc nó được inlined
- hoặc một
call
là thực sự phát ra
Nếu đó là inline, sau đó không có tham số nào được truyền, có nghĩa là các đối tượng không sử dụng có thể được gỡ bỏ (và thậm chí không được xây dựng) nếu trình biên dịch có thể chứng minh rằng các nhà xây dựng và destructors tham gia không thực hiện bất kỳ điều gì t làm việc. Nó hoạt động tốt cho các cấu trúc thẻ.
Khi cuộc gọi được phát ra, nó được phát ra với một quy ước gọi cụ thể. Mỗi trình biên dịch có tập hợp các quy ước gọi riêng của nó, chỉ định cách vượt qua các đối số khác nhau (this
con trỏ, v.v ...), thường cố gắng tận dụng lợi thế của các thanh ghi có sẵn.
Vì chỉ có khai báo của hàm được sử dụng để xác định quy ước gọi (model biên soạn riêng), sau đó nó là cần thiết để thực sự vượt qua các đối tượng ...
Tuy nhiên, nếu chúng ta đang nói về một cấu trúc rỗng , không có phương pháp và không có trạng thái, thì đây chỉ là một số bộ nhớ chưa được khởi tạo. Nó không nên chi phí nhiều, nhưng nó đòi hỏi không gian ngăn xếp (ít nhất, đặt nó).
Demo sử dụng tryout llvm:
struct tag {};
inline int useless(int i, tag) { return i; }
void use(tag);
int main() {
use(tag());
return useless(0, tag());
}
Cung cấp:
%struct.tag = type <{ i8 }>
define i32 @main() {
entry:
; allocate space on the stack for `tag`
%0 = alloca %struct.tag, align 8 ; <%struct.tag*> [#uses=2]
; get %0 address
%1 = getelementptr inbounds %struct.tag* %0, i64 0, i32 0 ; <i8*> [#uses=1]
; 0 initialize the space used for %0
store i8 0, i8* %1, align 8
; call the use function and pass %0 by value
call void @_Z3use3tag(%struct.tag* byval %0)
ret i32 0
}
declare void @_Z3use3tag(%struct.tag* byval)
Lưu ý:
- lời mời gọi làm
useless
đã được gỡ bỏ, và không có lý lẽ được xây dựng cho nó
- cách gọi tới
use
không thể bị xóa và do đó khoảng trống được phân bổ tạm thời (tôi hy vọng rằng các phiên bản mới không 0-khởi tạo bộ nhớ)
Kết quả sẽ khác nhau tùy theo trình biên dịch và mức tối ưu. Bạn sẽ phải thử nó. –
Tôi có 10 câu hỏi như thế này mỗi ngày, nếu tôi thử nghiệm mọi thứ tôi sẽ không nhận được bất kỳ công việc nào được thực hiện;), tôi đã đủ điều kiện cho câu hỏi với hai trình biên dịch mà tôi quan tâm. –
@Hassan: Tôi nghĩ bạn sẽ đã kết thúc trước khi viết một bài kiểm tra đơn giản thay vì viết toàn bộ câu hỏi :) –