2013-07-30 34 views
7

Tôi đang làm việc trên một cơ sở mã lớn, chuyển đổi một số mô-đun C cũ thành C++. Tôi muốn thêm một đối tượng C++ vào một cấu trúc, nhưng một số người dùng của cấu trúc này memset nó, điều không may cho đối tượng mà tôi muốn đặt trong cấu trúc.Cảnh báo thời gian biên dịch về memset trên dữ liệu không thuần cũ

Làm cách nào tôi có thể phát hiện tại thời điểm biên dịch mà việc này đang được thực hiện, để tôi có thể loại bỏ tất cả việc sử dụng memset trên cấu trúc như vậy không còn là POD nữa?

+0

'grep'ing cho' memset' có tăng quá nhiều kết quả để kiểm tra thủ công không? Nếu không, tôi không thấy một cách để trình biên dịch kiểm tra điều này. – arne

+0

@arne Đó là một phần của vấn đề, vâng. – Henrik

Trả lời

8

Tôi không chắc liệu trình biên dịch có giúp bạn bằng cách trực tiếp cung cấp một số cờ biên dịch hay không. Nếu có, tốt cho bạn. Dùng nó. Kết thúc câu chuyện.

Nếu không, thì có thể điều này sẽ giúp bạn. Vì bạn đang chuyển đổi mã của bạn từ C sang C++, điều đó có nghĩa là tất cả việc sử dụng memset là không có không gian tên std::. Vì vậy, tận dụng lợi thế của thực tế này và #define memset như:

#define memset memset_if_pod_else_error() 

Đây memset_if_pod_else_error là một chức năng được viết bởi bạn (nghĩa là bạn phải thực hiện nó). Bạn có thể làm cho nó mẫu để suy ra loại đối số và sau đó phát hiện cho dù loại là POD hay không. Nếu đó là POD, thì điều đó là tốt và gọi số std::memset nội bộ, nếu không thì sẽ tăng lỗi.

Các chức năng như std::enable_ifstd::is_pod sẽ giúp bạn triển khai chức năng này.

Đây là một bản demo tối thiểu của ý tưởng này:

#include <iostream> 
#include <type_traits> 
#include <cstring> 

auto ptr_memset = std::memset; //store this a pointer 

template<typename T> 
using VoidPtr = typename std::enable_if<std::is_pod<T>::value, void*>::type; 

#define memset memset_if_pod_else_error 

template<typename T> 
VoidPtr<T> memset_if_pod_else_error(T *data, int ch, size_t count) 
{ 
     return ptr_memset(data, ch, count); 
} 

struct pod {}; 
struct nonpod { nonpod() {} }; 

int main() 
{ 
    pod p; 
    nonpod np; 

    memset(&p, 0, sizeof(p)); 

    memset(&np, 0, sizeof(np)); //this is error! 
} 

Cuộc gọi thứ hai để memset tạo ra lỗi này:

error: no matching function for call to 'memset_if_pod_else_error'
memset(&np, 0, sizeof(np));
^~~~~~

Online Demo.

Hy vọng điều đó sẽ hữu ích.

+0

Cảm ơn, đây là một ý tưởng hay. Mô-đun C cũ được sử dụng hàng ngàn địa điểm trong mã C++ mới hơn, vì vậy thật không may cho tôi điều này sẽ chỉ giải quyết một phần vấn đề của tôi. – Henrik

+0

@Henrik: Tôi không thấy bất kỳ vấn đề gì. Bạn có thể thực hiện các chức năng cho phù hợp. Xem bản demo của tôi. Hy vọng rằng mang lại cho bạn * tốt hơn * ý tưởng. – Nawaz

1

Tôi không nghĩ rằng bạn có thể phát hiện việc sử dụng memset trên dữ liệu không phải POD lúc biên dịch.

Điều bạn có thể làm là thêm một số trường bổ sung được đặt trong hàm tạo và sau đó kiểm tra trong bất kỳ hàm thành viên nào khác. Một cái gì đó như thế này:

class X 
{ 
    const int MAGIC = 123456789; 
    int magic; 
    ... 
    public: 
    X() : magic(MAGIC) { ... } 
    ... 
    void do_stuff() 
    { 
     check_magic(); 
     ... 
    } 
    private: 
    void check_magic() 
    { 
     if (magic != MAGIC) { ... do something to indicate bad state ... }; 
    } 
}; 

Rõ ràng, điều này có thể được thực hiện "chỉ trên bản dựng gỡ lỗi".

+0

Nếu hàm tạo có thể được tạo thành 'constexpr', điều này cũng không thể được kiểm tra bằng một xác nhận tĩnh? – arne

+0

Vấn đề không phải là trong quá trình xây dựng, vấn đề là 'memset' không thực sự quan tâm bạn đang cho ăn gì, và chỉ đơn giản là bắn thẳng vào bất cứ thứ gì bạn cho vào - nghĩa là bạn phải kiểm tra 'ma thuật' sau (tiềm năng gọi)' memset'. –

2

Làm thế nào về điều này:

auto orig_memset = std::memset; 
#define memset checked_memset 

template <class T> 
void* checked_memset(T* ptr, int value, size_t num) { 
    static_assert(std::is_pod<T>::value, "memset on non-POD"); 
    return original_memset(data, value, num); 
} 

Hoặc, nếu bạn chỉ quan tâm đến việc tìm kiếm các vi phạm đối với struct cụ thể của bạn:

auto original_memset = std::memset; 
#define memset checked_memset 

template <class T> 
void* checked_memset(T* ptr, int value, size_t num) { 
    static_assert(!std::is_same<T, YOUR_STRUCT_HERE>::value, "memset used on YOUR_STRUCT_HERE"); 
    return original_memset(data, value, num); 
} 
+0

loại trả về có thể bị vô hiệu *, không phải T *. – wolfgang

+0

Điểm công bằng, cảm ơn. –

0

Trong trường hợp này isntead cố gắng tìm tất cả các vấn đề khu vực , Tôi sẽ đề nghị chỉ ngăn chặn chúng ở nơi đầu tiên. Cụ thể, không thêm bất kỳ khả năng C++ nào vào các cấu trúc C hiện có mà thay vào đó viết các lớp với một giao diện thích hợp có chứa các cá thể của các cấu trúc dữ liệu C. Sau đó, bạn duy trì khả năng tương thích ngược với cấu trúc và mã cũ cũng như thêm các khả năng C++ mới mà bạn quan tâm.

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