2016-07-13 31 views
11

Đây là một c chương trình đơn giản ++ sử dụng valarrays:Tại sao tối ưu hóa GCC không hoạt động với valaray?

#include <iostream> 
#include <valarray> 

int main() { 
    using ratios_t = std::valarray<float>; 

    ratios_t a{0.5, 1, 2}; 
    const auto& res (ratios_t::value_type(256)/a); 
    for(const auto& r : ratios_t{res}) 
     std::cout << r << " " << std::endl; 
    return 0; 
} 

Nếu tôi biên dịch và chạy nó như thế này:

g++ -O0 main.cpp && ./a.out 

Kết quả được như mong đợi:

512 256 128 

Tuy nhiên, nếu Tôi biên dịch và chạy nó như sau:

g++ -O3 main.cpp && ./a.out 

Đầu ra là:

0 0 0 

Cùng xảy ra nếu tôi sử dụng tham số tối ưu hóa -O1.

phiên bản GCC là (mới nhất trong Archlinux):

$ g++ --version 
g++ (GCC) 6.1.1 20160707 

Tuy nhiên, nếu tôi cố gắng với kêu vang, cả hai

clang++ -std=gnu++14 -O0 main.cpp && ./a.out 

clang++ -std=gnu++14 -O3 main.cpp && ./a.out 

tạo ra kết quả chính xác như nhau:

512 256 128 

phiên bản Clang là:

$ clang++ --version 
clang version 3.8.0 (tags/RELEASE_380/final) 

Tôi cũng đã thử với GCC 4.9.2 trên Debian, nơi thực thi ra kết quả đúng.

Đây có phải là lỗi có thể xảy ra trong GCC hay tôi đang làm điều gì sai? Bất cứ ai có thể sao chép này?

EDIT: Tôi đã quản lý để tạo lại sự cố cũng trên phiên bản Homebrew của GCC 6 trên Mac OS.

+0

Sử dụng http://melpon.org/wandbox nó xuất hiện những thay đổi hành vi từ 4.9.3 đến 5.1. – NathanOliver

+0

Thật không may, trong codebase của tôi, tôi cũng quản lý để tái tạo vấn đề tương tự (nhưng với uint32_t) ngay cả trên GCC 4.9.3, tuy nhiên nó hoạt động khi đưa vào ví dụ tối thiểu. Tôi đang điều tra ... – DoDo

Trả lời

6

valarrayauto không trộn đều.

Điều này tạo ra một đối tượng tạm thời, sau đó áp dụng operator/ với nó:

const auto& res (ratios_t::value_type(256)/a); 

Các libstdC++ valarray sử dụng các mẫu biểu để operator/ trả về một đối tượng nhẹ mà đề cập đến những lập luận ban đầu và đánh giá chúng một cách lười biếng. Bạn sử dụng const auto& làm cho mẫu biểu thức bị ràng buộc với tham chiếu, nhưng không kéo dài tuổi thọ của mẫu biểu thức đề cập, vì vậy khi đánh giá xảy ra tạm thời đã hết phạm vi và bộ nhớ của nó đã bị tái sử dụng.

Nó sẽ làm việc tốt nếu bạn làm:

ratios_t res = ratios_t::value_type(256)/a; 
+0

Cảm ơn bạn đã trả lời chi tiết. Tôi sẽ chấp nhận nó. Tôi chỉ muốn lưu ý rằng ngay cả khi tôi viết 'tự động res (ratios_t :: value_type (256)/a)', tôi vẫn nhận được kết quả tương tự với tối ưu hóa được bật. Tuy nhiên, đề xuất của bạn hoạt động (tức là không sử dụng 'tự động'). Với cả hai mã clang và msvc gốc đều hoạt động chính xác. – DoDo

+0

Có, vì 'tự động' suy ra loại mẫu biểu thức có chứa tham chiếu đến tạm thời đã hết hạn. Bạn cần phải rõ ràng tạo ra một 'valarray', để buộc việc đánh giá xảy ra trước khi tạm thời biến mất. Như tôi đã nói, 'auto' và' valarray' không hòa hợp tốt. –

+0

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57997 là một vấn đề rất giống nhau. –

3

Đó là kết quả của việc thực hiện bất cẩn của operator/ (const T& val, const std::valarray<T>& rhs) (và có lẽ hầu hết các nhà khai thác khác trên valarrays) sử dụng đánh giá lười biếng:

#include <iostream> 
#include <valarray> 

int main() { 
    using ratios_t = std::valarray<float>; 

    ratios_t a{0.5, 1, 2}; 
    float x = 256; 
    const auto& res (x/a); 
    // x = 512; // <-- uncommenting this line affects the output 
    for(const auto& r : ratios_t{res}) 
     std::cout << r << " "; 
    return 0; 
} 

Với "x = 512" dòng nhận xét ra, đầu ra là

512 256 128 

Bỏ ghi chú rằng dòng và đầu ra thay đổi thành

1024 512 256 

Vì trong ví dụ của bạn, đối số bên trái của toán tử phân chia là tạm thời, kết quả là không xác định.

CẬP NHẬT

Như Jonathan Wakely đúng pointed out, việc thực hiện lười biếng đánh giá dựa trở thành một vấn đề trong ví dụ này là do việc sử dụng auto.

+0

Cảm ơn câu trả lời của bạn. Jonathan là người đầu tiên nên tôi chấp nhận câu trả lời của anh ấy, nhưng anh cũng rất thông tin. Quá xấu SO không cho phép bạn chấp nhận nhiều câu trả lời :-). – DoDo

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