2016-01-16 12 views
11

Tôi có ví dụ sau:Sử dụng t (* this) kết quả RuntimeError, trong khi t (std :: ref (* this) không

#include <iostream> 
#include <functional> 

struct Tmr { 
    typedef std::function<void(void)> Callback; 
    Callback cb; 

    Tmr(Callback cb_) : 
     cb(cb_) 
    { 
    } 

    void timeout() 
    { 
     cb(); 
    } 
}; 

struct Obj { 
    struct Tmr t; 

    Obj() : 
     t(std::ref(*this)) 
    { 
    } 

    void operator()() 
    { 
     std::cout << __func__ << '\n'; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    Obj o; 

    o.t.timeout(); 

    return 0; 
} 

này chạy tốt, nhưng ban đầu tôi đã có nhà xây dựng của Obj như:.

Obj() : 
    t(*this) 

những kết quả trong một lỗi runtime tôi đoán đây là bởi vì chỉ có một tham chiếu đến hàm thành viên được lưu trữ trong callback của tôi, và không phải là đối tượng để gọi các thành viên trên

những gì tôi. không hiểu là những gì std::ref làm khi tôi làm Obj() : t(std::ref(*this)) và lý do tại sao điều này làm cho chương trình hoạt động. Bất cứ ai có thể làm sáng tỏ những gì đang xảy ra và nó hoạt động như thế nào?

+0

Không có 'Obj(): t (* this)' hoạt động tốt. 'Callback' của bạn là một loại functor, mà' Obj' của bạn cũng là. –

+0

@ Jean-BaptisteYunès Bạn đang nói trình biên dịch tạo mã không hợp lệ, vì 'Obj(): t (* this)' bị treo trong thời gian chạy, nhưng nó sẽ hoạt động tốt? – binary01

+2

Nó hoạt động trên trình biên dịch g ++ std C++ 11 của tôi, và tôi không thể thấy tại sao nó không hoạt động cho bạn. –

Trả lời

5

Khi bạn không vượt qua tham chiếu, bạn sao chép *this trước khi t được khởi tạo - có nghĩa là bạn đang sao chép t và thành viên gọi lại trước khi chúng được khởi tạo, hành vi không xác định.

(Và các nhà xây dựng bản sao của std::function có khả năng cố gắng sao chép những gì đang được trỏ đến bởi một con trỏ uninitialised, đó là những gì gây ra vụ tai nạn thực tế.)

1

Bạn đang bị treo vì sao chép các đối tượng gọi lại chưa được khởi tạo. Bạn có thể thấy chuỗi sự kiện bên dưới:

1. Copy constructor of Obj is called in t(*this) 
2. Copy constructor of Tmr is called as t is a member of Obj 
3. Copy constructor of Callback is called as cb is a member of Tmr 
4. Execution fails while trying to copy from uninitialized Callback object. 

Bằng cách sử dụng tiêu chuẩn :: bạn bỏ qua việc tạo bản sao Obj; đó là lý do tại sao nó không sụp đổ.

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