2017-07-02 24 views
12

Nhìn vào mã này:Tại sao các trình biên dịch không tối ưu hóa điều này?

struct Data { 
}; 

struct Init { 
    Data *m_data; 

    Init() : m_data(new Data) { } 
    ~Init() { 
     delete m_data; 
    } 
}; 

class Object { 
    private: 
     const int m_initType; 
     Data *m_data; 
    public: 
     Object(const Init &init) : m_initType(0), m_data(init.m_data) { } 
     Object(Init &&init) : m_initType(1), m_data(init.m_data) { init.m_data = nullptr; } 
     ~Object() { 
      if (m_initType==1) { 
       delete m_data; 
      } 
     } 
}; 

void somefunction(const Object &object); // it is intentionally not defined 

void callInitA() { 
     Init x; 
     somefunction(x); 
} 

void callInitB() { 
     somefunction(Init()); 
} 

Như Object::m_initType là const, nó không thay đổi sau khi xây dựng. Vì vậy, theo lý thuyết, trong callInitA và trong callInitB, trình biên dịch biết giá trị của m_initType khi nó inline ~Object(). Tuy nhiên, cả gcc và clang fails to apply tối ưu hóa này và cả hai đều kiểm tra giá trị của m_initType.

Tại sao lại như vậy? Có một số quy tắc ngôn ngữ chống lại việc tối ưu hóa này hay các trình biên dịch không làm loại tối ưu hóa này?

(Câu hỏi này liên quan chặt chẽ đến this, nhưng nó là một câu hỏi cụ thể hơn, tôi hy vọng tôi có thể nhận được một câu trả lời cho việc này)

+0

'Init g; void somefunction (Object object) {object. ~ Object(); đối tượng mới (& đối tượng) (g);} 'có thể? –

+4

Dưới đây là một ví dụ nhỏ hơn nhiều mà tôi nghĩ rằng chứng minh cùng một vấn đề: https://godbolt.org/g/zTyctM - nếu bạn nhận xét 'somefunction' thì toàn bộ điều được tối ưu hóa, nhưng với' somefunction' được gọi là trình biên dịch tạo ra một kiểm tra cho một cái gì đó mà "không thể xảy ra." –

+2

MSVC++ áp dụng tối ưu hóa này. Một số có, một số thì không, các trình tối ưu hóa không được tạo ra như nhau. –

Trả lời

0

Object destructor không inlined trong ví dụ của bạn và bạn có 2 lời gọi, nơi trong một m_initType là 1 và trong một là 0. Vì vậy, trình biên dịch phải hỗ trợ cả hai phiên bản. Ngoài ra, tôi giả sử rằng mã thực sự của bạn phức tạp hơn một chút so với ví dụ của bạn, vì vậy trình biên dịch có thể quyết định rằng mã toàn bộ nội tuyến là tốn kém hơn so với việc giữ phiên bản chung với một 'if' bên trong.

+0

Bạn có thể viết 'inline' ở phía trước trình hủy và biên dịch với' g ++ -O3 -Winline -Werror' - tôi nghĩ bạn sẽ thấy nó không thay đổi gì cả. –

+1

Tôi nghĩ bạn đã hiểu lầm câu hỏi của tôi. Đối tượng destructor ** là ** nội tuyến, vì nó có thể được nhìn thấy từ việc tháo gỡ. Mã của tôi là phức tạp hơn, tất nhiên, nhưng tối ưu hóa mất tích này xảy ra trong mã tôi đăng. – geza

+0

@JohnZwinck Tôi không thể đoán được điều gì đã ngụ ý. Tôi chỉ trả lời cho bất cứ điều gì tôi thấy trong câu hỏi :) tối ưu hóa là một cái gì đó tự nguyện và không được thi hành theo tiêu chuẩn. Tương tự cho 'nội tuyến' - bạn có thể viết nhiều như bạn muốn, nhưng theo tiêu chuẩn thì nó chỉ là đề xuất. Do đó trình biên dịch được tự do bỏ qua 'nội dòng' nếu nó không thấy bất kỳ lợi ích nào. – Noname

3

Để trả lời cho dù có bất kỳ quy tắc bằng ngôn ngữ mà cấm loại tối ưu hóa, đây là mất của tôi

Từ [dcl.type.cv]

Trừ rằng bất kỳ thành viên lớp tuyên bố có thể thay đổi có thể được sửa đổi, bất kỳ nỗ lực để sửa đổi một đối tượng const trong suốt cuộc đời của nó dẫn đến hành vi không xác định.

Và về lý thuyết, trình tối ưu hóa có thể giả định an toàn m_initType sẽ không bao giờ thay đổi sau khi khởi tạo. Điều này tất nhiên có thể được sử dụng để suy luận xem các chi nhánh trong ~Object sẽ được thực hiện tại thời gian biên dịch.

Điều đó nói rằng, người tối ưu hóa được tự do làm bất cứ điều gì miễn là hành vi được quan sát vẫn giữ nguyên, do đó, chúng cũng được tự do bỏ qua const. Để làm cho vấn đề phức tạp hơn đối với trình tối ưu hóa, có một hàm được khai báo trước nhưng không được xác định trong kết hợp, trình tối ưu hóa có thể chỉ từ bỏ sau đó để làm bất kỳ điều gì có ích với thông tin.

Comparison of defined vs undefined function

Nếu chức năng được xác định sau này, gcc và Clang cả tối ưu hóa tất cả mọi thứ đi. Tuy nhiên, lưu ý, trong trường hợp cụ thể này, chúng sẽ là still do this ngay cả khi không có bất kỳ const.

This post có thể quan tâm

+1

Cảm ơn câu trả lời. Đúng, nếu định nghĩa được hiển thị cho trình biên dịch, nó có thể thực hiện tối ưu hóa thông thường. Tôi đã chỉnh sửa câu hỏi của mình để làm rõ rằng 'somefunction' là cố ý không được xác định. – geza

+0

Trích dẫn này không đủ nếu 'm_initType' không phải là một đối tượng ... (tiêu chuẩn có định nghĩa đối tượng khá hạn chế) –

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