2010-02-09 52 views
5

Tôi đã nói biến tham chiếu phải được khởi tạo trong danh sách khởi tạo, nhưng tại sao điều này sai?khởi tạo tham chiếu trong danh sách khởi tạo

class Foo 
    { 
    public: 
     Foo():x(0) {  
     y = 1; 
     } 
    private: 
     int& x; 
     int y; 
    }; 

Vì 0 là đối tượng tạm thời? Nếu vậy, loại đối tượng nào có thể tham chiếu bị ràng buộc? Đối tượng có thể lấy địa chỉ?

Cảm ơn!

Trả lời

15

0 không phải là một lvalue, đó là một giá trị. Bạn không thể sửa đổi nó, nhưng bạn đang cố gắng liên kết với một tham chiếu nơi nó có thể được sửa đổi.

Nếu bạn thực hiện tham chiếu const, nó sẽ hoạt động như mong đợi. Hãy xem xét điều này:

int& x = 0; 
x = 1; // wtf :(

Điều này rõ ràng là không cần thiết. Nhưng const& 's có thể bị ràng buộc để temporaries (rvalues):

const int& x = 0; 
x = 1; // protected :) [won't compile] 

Lưu ý rằng cuộc sống thời điểm tạm thời được kết thúc vào lúc kết thúc các nhà xây dựng. Nếu bạn thực hiện lưu trữ tĩnh cho hằng số của mình, bạn sẽ an toàn:

class Foo 
{ 
public: 
    static const int Zero = 0; 

    Foo() : x(Zero) // Zero has storage 
    { 
     y = 1; 
    } 
private: 
    const int& x; 
    int y; 
}; 
+0

Ví dụ cụ thể trong hàm dựng của nó mặc dù vẫn sẽ thất bại thảm hại nếu anh ta khai báo biến thành viên 'const'. – Omnifarious

+1

@Omnifarious: Làm thế nào? – GManNickG

+0

Điều gì xảy ra khi tạm thời 0 bị hủy? Làm thế nào về nếu địa chỉ của nó được thực hiện và dereferenced? – Omnifarious

0

Tham chiếu dài hạn phải được liên kết với lvalue. Về cơ bản, như bạn hùng hồn đặt nó, một đối tượng có một địa chỉ xác định. Nếu chúng bị ràng buộc tạm thời sẽ bị phá hủy trong khi tham chiếu vẫn đang tham chiếu nó và kết quả là không xác định.

Tham chiếu const sống ngắn (biến hàm cục bộ và đối số hàm) có thể bị ràng buộc theo thời gian. Nếu có, tạm thời được đảm bảo không bị phá hủy cho đến khi tham chiếu vượt quá phạm vi.

đang

diễn:

#include <iostream> 

class Big { 
public: 
    Big() : living_(true), i_(5) { // This initialization of i is strictly legal but 
     void *me = this;   // the result is undefined. 
     ::std::cerr << "Big constructor called for " << me << "\n"; 
    } 
    ~Big() { 
     void *me = this; 
     living_ = false; 
     ::std::cerr << "Big destructor called for " << me << "\n"; 
    } 

    bool isLiving() const { return living_; } 
    const int &getIref() const; 
    const int *getIptr() const; 

private: 
    ::std::string s_; 
    bool living_; 
    const int &i_; 
    char stuff[50]; 
}; 

const int &Big::getIref() const 
{ 
    return i_; 
} 

const int *Big::getIptr() const 
{ 
    return &i_; 
} 

inline ::std::ostream &operator <<(::std::ostream &os, const Big &b) 
{ 
    const void *thisb = &b; 
    return os << "A " << (b.isLiving() ? "living" : "dead (you're lucky this didn't segfault or worse)") 
      << " Big at " << thisb 
      << " && b.getIref() == " << b.getIref() 
      << " && *b.getIptr() == " << *b.getIptr(); 
} 

class A { 
public: 
    A() : big_(Big()) {} 

    const Big &getBig() const { return big_; } 

private: 
    const Big &big_; 
}; 

int main(int argc, char *argv[]) 
{ 
    A a; 
    const Big &b = Big(); 
    const int &i = 0; 
    ::std::cerr << "a.getBig() == " << a.getBig() << "\n"; 
    ::std::cerr << "b == " << b << "\n"; 
    ::std::cerr << "i == " << i << "\n"; 
    return 0; 
} 

Và kết quả:

Big constructor called for 0x7fffebaae420 
Big destructor called for 0x7fffebaae420 
Big constructor called for 0x7fffebaae4a0 
a.getBig() == A living Big at 0x7fffebaae420 && b.getIref() == -341121936 && *b.getIptr() == -341121936 
b == A living Big at 0x7fffebaae4a0 && b.getIref() == 0 && *b.getIptr() == 0 
i == 0 
Big destructor called for 0x7fffebaae4a0 
0

Vâng, bạn có thể không bao giờ thay đổi nó, 0 có thể bất cứ điều gì không bao giờ bình đẳng khác hơn 0.

thử

class Foo 
    { 
    public: 
     Foo(int& a):x(a) {  
     y = 1; 
     } 
    private: 
     int& x; 
     int y; 
    }; 

Alte rnatively, bạn có thể làm điều này nếu tham chiếu của bạn là hằng số bởi vì sau đó 0 chỉ có thể bằng không

+0

Tham chiếu trở nên không hợp lệ khi hàm tạo được thực hiện. :/ – GManNickG

+0

Không, tham chiếu trở nên không hợp lệ khi int được truyền vào hàm khởi tạo nằm ngoài phạm vi trong hàm gọi – Steve

+0

Vâng, các câu trả lời chỉnh sửa bài đăng khá thấp. Bạn nên đề cập đến "Tôi đã sửa chữa." không, "Bạn sai rồi." :( – GManNickG

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