2011-06-21 35 views
7

Tôi đã gặp một trường hợp gần đây, nơi tôi có chức năng thành viên const thực hiện một thao tác và trả về kết quả. Ví dụ,Có cách nào tốt để đảm bảo kết quả hàm C++ không bị bỏ qua?

class Foo { ... 
    Foo add(Foo const & x) const; 
} 

Nhưng ai đó đã vô tình gọi nó như nó đã được cập nhật các đối tượng this (bỏ qua kết quả):

Foo a = ...; 
Foo b = ...; 
a.add(b); 

(. Lỗi này đã thực sự được giới thiệu bởi một refactoring không hoàn hảo)

Có cách nào để làm cho dòng cuối cùng ở trên kích hoạt lỗi hoặc cảnh báo không? Điều tốt nhất tiếp theo sẽ là thời gian chạy, chủ yếu được giải quyết bằng mẫu sau. Tuy nhiên, nó sẽ tiêu diệt tối ưu hóa giá trị trả về, như được xem bởi kết quả truy cập.

template<typename T> 
class MustTake { 
    T & obj; 
    bool took; 
public: 
    MustTake(T o) : obj(o), took(false) {} 
    ~MustTake() { if (!took) throw "not taken"; } 
    operator T&() { took = true; return obj;} 
}; 

struct Counter { 
    int n; 
    Counter() : n(0) {} 
    Counter(Counter const & c) : n(c.n+1) {} 
    ~Counter() {} 
}; 

Counter zero1() { 
    return Counter(); 
} 

MustTake<Counter> zero2() { 
    return Counter(); 
} 

int main() { 
    Counter c1 = zero1(); 
    printf("%d\n",c1.n); // prints 0 
    Counter c2 = zero2(); 
    printf("%d\n",c2.n); // prints 1 
    zero1(); // result ignored 
    zero2(); // throws 
    return 0; 
} 

Tôi cho rằng tôi có thể cải thiện sự kém hiệu quả bằng cách sử dụng một macro để MustTake <> chỉ gỡ lỗi và một không-op cho phát hành.

Tôi đang tìm giải pháp biên dịch. Nếu không, tôi đang tìm giải pháp thời gian chạy tốt nhất.

+0

Trình biên dịch nào bạn đang sử dụng? –

+0

Nếu bạn đang sử dụng GCC, tôi nghĩ rằng nó có cờ '-Wunused-result' để bật cảnh báo cho điều đó. – Xeo

+0

Chọn một tên phương pháp tốt hơn sẽ là gợi ý của tôi. Nếu tôi đọc 'a.add (b) 'tôi sẽ nghĩ ngay lập tức. Làm thế nào về 'a.newListWithHead (b)' hoặc một cái gì đó tương tự, tùy thuộc vào những gì đang thực sự xảy ra? Không gọn gàng như 'add', nhưng việc thêm vào không thực sự là những gì bạn đang làm ở đây. – msandiford

Trả lời

8

Đây là những thuộc tính chức năng dành cho (documentation) trong GCC và Clang, nhưng không thể di chuyển được, ví dụ: MSVC.

class Foo { ... 
    __attribute__((warn_unused_result)) 
    Foo add(Foo const & x) const; 
} 

Các tài liệu nói nó được sử dụng trên reallocví dụ, nhưng nó không xuất hiện trên bất kỳ chức năng tiêu chuẩn khác trên hệ thống của tôi.

Bạn cũng có thể quan tâm đến việc sử dụng máy phân tích tĩnh Clang, theo dõi luồng dữ liệu qua các cuộc gọi hàm và có thể cho bạn cảnh báo tốt hơn.

+0

Nó được sử dụng trên khá nhiều syscalls trên hệ thống của tôi (debian sid) - ví dụ, 'read()' và 'write()'. Trong glibc, nó là '# define'd thành' __wur' (đây là một chi tiết thực hiện của thư viện C, dĩ nhiên) – bdonlan

+0

Huh, tôi không bắt được nó với 'grep' bởi vì nó không tìm thấy định nghĩa' __wur '. –

+0

Bạn có thể "làm cho nó di động" bằng cách gói nó bên trong một vĩ mô mà kiểm tra nếu trình biên dịch là GCC hoặc kêu vang. Đối với MSVC người ta có thể sử dụng cờ trình biên dịch '/ W3' để kích hoạt cảnh báo về các biến không sử dụng. [Xem tại đây] (https://msdn.microsoft.com/en-us/library/c733d5h9.aspx). Mặc dù điều này cho phép nó cho * tất cả * lần xuất hiện. – rwols

0

Nếu điều quan trọng là một giá trị trả về không được bỏ qua bởi người gọi của một hàm, mẫu dont_ignore có thể được sử dụng như sau

TRƯỚC :

int add(int x, int y) 
{ 
    return x + y; 
} 

SAU:

dont_ignore<int> add(int x, int y) 
{ 
    return x + y; 
} 

Khi người gọi của hàm không sử dụng giá trị trả lại, một ngoại lệ được ném. Định nghĩa của dont_ignore:

template<class T> 
struct dont_ignore 
{ 
    const T  v; 
    bool  used; 

    dont_ignore(const T& v) 
     : v(v), used(false) 
    {} 

    ~dont_ignore() 
    { 
     if (!used) 
      throw std::runtime_error("return value not used"); 
    } 

    operator T() 
    { 
     used = true; 
     return v; 
    } 
}; 
+0

Quay lại tham chiếu: http://zumalifeguard.wikia.com/wiki/Code_C%2B%2B_Functions_to_Prevent_Clients_Ignoring_Return_Values – zumalifeguard

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