Là hàm hủy của một đối tượng cục bộ bên trong một vòng lặp được đảm bảo được gọi trước lần lặp tiếp theo?


11

Khi tôi có một vòng lặp và bên trong vòng lặp này tạo ra một biến ngăn xếp mới (không phân bổ nó trên heap và biến giữ nó được khai báo bên trong thân vòng lặp), là hàm hủy của đối tượng này được đảm bảo được gọi trước khi lần lặp tiếp theo bắt đầu, hoặc có thể vòng lặp unrolling bởi trình biên dịch thay đổi một cái gì đó về điều đó?


1
Vòng lặp unrolling mỗi se sẽ không thay đổi thứ tự thực hiện. Tuy nhiên, song song hóa vòng lặp có thể làm điều này.
Adrian Mole

Câu trả lời:


8

Từ n4800:

§6.3.3 Phạm vi khối :

Một tên được khai báo trong một khối (8.3) là cục bộ của khối đó; nó có phạm vi khối. Phạm vi tiềm năng của nó bắt đầu tại điểm khai báo (6.3.2) và kết thúc ở cuối khối. Một biến được khai báo ở phạm vi khối là một biến cục bộ.

§10.3.6 Công cụ phá hủy :

Một hàm hủy được gọi ngầm [...] khi khối trong đó một đối tượng được tạo ra (8.7)

§4.1.1 Tóm tắt máy :

Điều khoản này đôi khi được gọi là quy tắc của as as if if, bởi vì việc triển khai được tự do bỏ qua mọi yêu cầu của tài liệu này miễn là kết quả đó như thể yêu cầu đã được tuân thủ, theo như có thể được xác định từ hành vi có thể quan sát được của chương trình .

[Nhấn mạnh của tôi]

Vì vậy, vâng. Biến của bạn đi ra khỏi phạm vi ở cuối vòng lặp (là một khối) và do đó hàm hủy của nó được gọi xa như bất kỳ ai quan sát hành vi của chương trình có thể biết .


1
Không có gì trong đó về KHI hàm hủy được gọi.
stark

2
@stark Điều cho phép họ làm điều này là quy tắc as-if. Tiêu chuẩn chỉ xác định hành vi của máy trừu tượng. Không chắc chắn nếu cần phải đi vào tất cả các chi tiết trong câu trả lời ở đây.
Max Langhof

2
@stark Đây là, IMO, không liên quan đến câu hỏi. Bạn cũng có thể nói rằng các hàm hủy có thể được nội tuyến, và do đó không called. Hoặc, nếu chúng có hiệu quả (quy tắc như nếu) không làm gì, có thể không có lắp ráp cho các hàm hủy như vậy được tạo ra.
Daniel Langr


2
@stark đâu được định nghĩa ? Lưu ý rằng cuộc thảo luận này không có chủ đề cho câu hỏi. Bạn có thể hỏi một câu hỏi riêng về vấn đề này.
Daniel Langr

8

Đúng. Dễ hình dung hơn khi bạn xem xét các "khối" trong đó bạn khai báo một biến, tức là giữa cặp niềng răng nào. Vòng lặp là một khối trong chính nó và khi nó đạt đến khung đóng, trước lần lặp tiếp theo, tất cả các hàm hủy của các biến lưu trữ tự động được khai báo trong vòng lặp được gọi.

có thể lặp unrolling bởi trình biên dịch thay đổi một cái gì đó về điều đó?

Theo nguyên tắc thông thường, đừng nghĩ về những gì trình biên dịch sẽ tối ưu hóa, bởi vì nó vẫn cần đảm bảo hoạt động của chương trình của bạn, bất kể nó làm gì để tối ưu hóa nó. Trong trường hợp đó, việc hủy đăng ký vòng lặp sẽ không thay đổi bất cứ điều gì đối với hiệu ứng đó nếu nó xảy ra.


2
+1 cho quy tắc ngón tay cái, khi viết mã người ta không nên lo lắng về nội bộ trình biên dịch. Sẽ thêm một cái gì đó theo tinh thần tương tự vào câu trả lời của tôi, nhưng bây giờ nó đã có sẵn
idclev 463035818

copy-elision và RVO thay đổi hành vi chương trình, phải không?
Jean-Baptiste Yunès

@ Jean-BaptisteYunès Họ có khả năng, tuy nhiên, tiêu chuẩn cho phép họ quá[class.copy.elision]
ChrisMM

Không chỉ là cặp niềng răng . Bạn có thể viết for(...) X x{};xđối tượng sẽ được xây dựng + hủy trong mỗi lần lặp. Bản demo trực tiếp . Một phần Tiêu chuẩn có liên quan là stmt.iter / 2 .
Daniel Langr

@DanielsaysreinstateMonica Theo §9.5.2, [stmt.iter]nó hoàn toàn tương đương (nhấn mạnh của tôi): "Nếu phần thay thế trong câu lệnh lặp là một câu lệnh đơn và không phải là câu lệnh ghép, thì như thể nó được viết lại thành câu lệnh ghép tuyên bố ban đầu. ". Về bản chất, có hoặc không có dấu ngoặc nhọn cho một câu lệnh có nghĩa chính xác là cùng một thứ và dấu ngoặc nhọn là ẩn. Tôi đã bỏ qua nó cho rõ ràng.
JBL

2

Hàm hủy được gọi cho mỗi lần lặp. Vì vậy, trong một số trường hợp, việc khai báo một biến bên ngoài vòng lặp thay vì trong vòng lặp sẽ nhanh hơn . Giả sử trường hợp sau:

std::string temp;
for(int i = 0; i < 10; ++i){
    temp = arr[i];
    doSomething(temp);
}

Hàm hủy không được gọi khi sử dụng vòng lặp được thực thi. Nó chỉ ghi đè temp.

Nhưng nếu bạn sử dụng std::string temp = arr[i]hàm tạo và hàm hủy được gọi cho mỗi lần lặp. Tôi nghĩ rằng điều này thêm một chút thời gian chạy trong trường hợp bạn có một vòng lặp được thực hiện rất thường xuyên.


lưu ý rằng các hàm hủy có được gọi hay không không chỉ là một câu hỏi về hiệu suất. Khi bạn có loại RAII, bạn đặc biệt muốn hàm hủy được gọi trên mỗi lần lặp
idclev 463035818

không chắc đó là sự thật. Không phải kẻ hủy hoại nội dung 'temp' đang giữ từ lần lặp trước được gọi đúng khi temp được gán lại với giá trị mới?
dùng1282931

Tôi cũng không chắc chắn 100%. Đúng câu trả lời của tôi nếu bạn tìm thấy một cái gì đó sai. :)
Julian Schnabel


0

Tất nhiên, dtor được gọi ở cuối vòng lặp và không kiểm soát vòng lặp không nên sửa đổi hành vi này, vì bất kỳ tối ưu hóa nào khác (tối ưu hóa không nên sửa đổi hành vi chương trình), ngoại trừ một số loại RVO và tương tự có thể loại bỏ một số sáng tạo đối tượng giả về ngữ nghĩa .

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.