2011-09-07 33 views
5

Giả sử đối tượng làvì vậy loại "này" là gì? Tại sao "này" không phải là một lvalue?

class A { 
public : void Silly(){ 
    this = 0x12341234; 
} 

Tôi biết tôi sẽ nhận được biên dịch lỗi 'này "không phải là một giá trị trái.' Nhưng sau đó nó cũng không phải là tạm thời. Vậy tuyên bố giả thuyết về "cái này" là gì?

Trình biên dịch: Trình biên dịch GCC 4.2 trên mac.

+4

Bắt buộc 'try {this = madness; } catch (...) {this = sparta; } ' – corsiKa

+0

Không quan tâm, trình biên dịch nào cung cấp cho bạn thông báo này? –

+0

@Oli: Nếu mã được thay đổi thành 'this = (A *) 0x12341234;', VC++ reports "* toán hạng bên trái phải là l-value *" - loại tương tự. – ildjarn

Trả lời

6

Đối với một số loại X, this có loại X* this;, nhưng bạn không được phép gán cho nó, vì vậy mặc dù nó không thực sự có loại X *const this, nó hoạt động gần như là ngăn chặn chuyển nhượng đi. Chính thức, đó là một prvalue, là cùng một danh mục giống như một chữ số nguyên, vì vậy cố gắng gán cho nó tương đương với việc cố gán giá trị khác cho 'a' hoặc 10.

Lưu ý rằng trong đầu C++, this là một giá trị trái - gán cho this được phép - bạn đã làm điều đó để xử lý việc phân bổ bộ nhớ cho một đối tượng, mơ hồ tương tự như quá tải newdelete cho lớp (mà wasn Chưa được hỗ trợ tại thời điểm đó).

+0

OK, đã hiểu. Tôi đã xóa nhận xét không cần thiết của mình. – AnT

3

Đối với một điều, this không phải là biến - đó là từ khóa. Khi được sử dụng làm giá trị, loại của nó là A * hoặc A const *. Trong C++ hiện đại, việc gán cho this bị cấm. Bạn cũng không thể lấy địa chỉ của this. Nói cách khác, nó không phải là một giá trị hợp lệ.

+2

"* Khi được sử dụng làm giá trị, loại của nó là' A * 'hoặc' A * const'. * "Ý của bạn là' A * 'hoặc' A const * '. – ildjarn

+0

Phải. Damn nhầm lẫn về con trỏ constness. –

+2

@Seva: Có một quy tắc đơn giản giúp giữ cho nó rõ ràng. Nếu bạn nhìn vào một khai báo như 'T * p;', 'T' là kiểu đích và' p' là tên của chính con trỏ, với '*' như là một "bức tường" giữa hai cái. Nếu bạn đặt 'const' (hoặc' volatile') ở phía con trỏ của bức tường, nó sẽ ảnh hưởng đến con trỏ. Nếu bạn đặt nó vào "loại" bên của bức tường, nó ảnh hưởng đến loại con trỏ trỏ đến. –

1

Bạn nhận được lỗi trình biên dịch vì this là một con trỏ const đến thể hiện của lớp cùng loại với lớp đó. Bạn không thể gán cho nó mặc dù bạn có thể sử dụng nó để thay đổi các thành viên lớp khác trong các phương thức không đủ điều kiện, các phương thức gọi và các toán tử. Cũng lưu ý vì nó là một ví dụ mà các phương thức tĩnh không có một con trỏ this.

Giả định:

class Whatever 
{ 
    // your error because this is Whatever* const this; 
    void DoWhatever(const Whatever& obj) { this = &obj; } 

    // this is ok 
    void DoWhatever(const Whatever& obj) { *this = obj; } 

    // error because this is now: const Whatever* const this; 
    void DoWhatever(const Whatever& obj) const { *this = obj; } 

    // error because this doesn't exist in this scope 
    static void DoWhatever(const Whatever& obj) { *this = obj; } 
}; 
4

Nó là không thể để cung cấp một "tuyên ngôn" cho this. Không có cách nào để "tuyên bố" một rvalue trong C + +. Và this là một giá trị, như bạn đã biết.

Độ chính xác và tỷ lệ rvalueness là các thuộc tính của các biểu thức tạo ra các giá trị này, chứ không phải thuộc tính của khai báo hoặc đối tượng. Về vấn đề đó, người ta thậm chí có thể lập luận rằng nó không thể tuyên bố một lvalue hoặc. Bạn khai báo một đối tượng. Lvalue là cái được tạo ra khi bạn sử dụng tên của đối tượng đó như là một biểu thức. Trong ý nghĩa đó, cả hai "tuyên bố một rvalue" và "để tuyên bố một lvalue" là biểu thức oxymoron.

Câu hỏi của bạn dường như cũng gợi ý rằng các thuộc tính "là một khoản hoa hồng" và "tạm thời" được bổ sung bằng cách nào đó, tức là mọi thứ được cho là một giá trị hoặc tạm thời. Trong thực tế, tài sản "tạm thời" không có kinh doanh ở đây. Tất cả các biểu thức là một trong hai giá trị hoặc giá trị. Và this xảy ra là một rvalue.

Mặt khác, thời gian có thể được coi là giá trị hoặc theo giá trị, tùy thuộc vào cách bạn truy cập tạm thời.

P.S. Lưu ý, BTW, rằng trong C++ (như trái ngược với C) chức năng bình thường là lvalues.

+0

Vâng, đến từ nền C tôi có xu hướng xem tờ khai của rvalue là "const lvalue-type" –

+0

@Ajeet: Điều đó thật kỳ lạ. Ngôn ngữ C không khác nhiều so với C++ trong vấn đề này. Trong ngôn ngữ C, khai báo 'const int' khai báo một giá trị ** **, không phải là một giá trị rvalue. – AnT

+0

Trong khi bạn không thể khai báo một giá trị, bạn có thể (ví dụ) khai báo/xác định một giá trị của một loại mà giá trị đó có thể được gán mà không cần chuyển đổi. –

2

Để trả lời phần thứ hai, "tại sao là this không phải là một giá trị trái", tôi suy đoán như động lực thực tế của ủy ban, nhưng ưu điểm bao gồm:

  1. gán để this không có ý nghĩa nhiều logic , do đó, không có nhu cầu cụ thể cho nó xuất hiện ở phía bên tay trái của các bài tập. Làm cho nó một rvalue nhấn mạnh rằng điều này không có ý nghĩa nhiều bằng cách cấm nó, và có nghĩa là tiêu chuẩn không phải xác định những gì sẽ xảy ra nếu bạn làm điều đó.
  2. làm cho nó trở thành một rvalue ngăn cản bạn lấy một con trỏ đến nó, do đó làm giảm việc thực hiện bất kỳ cần phải cung cấp nó với một địa chỉ, giống như một biến tự động biến đổi register. Ví dụ, nó có thể dành một thanh ghi trong các hàm thành viên không tĩnh để lưu trữ this. Nếu bạn lấy tham chiếu const, thì trừ khi sử dụng cho phép tối ưu hóa xảo quyệt, nó cần phải được sao chép ở đâu đó có địa chỉ, nhưng ít nhất nó không cần địa chỉ giống nhau nếu bạn làm điều đó hai lần liên tiếp nhanh chóng nếu this là biến được khai báo.
+0

Để xem bằng chứng trong pudding, tôi đã chơi với điều này: const int i = 10; * (int *) ((void *) & i) = 20; Đó là hợp lệ. Nhưng tôi không thể làm như vậy với 'điều này' như tôi không thể áp dụng và để 'này'. –

+1

Có, mặc dù IIRC tiêu chuẩn không thực sự xác định "chương trình hợp lệ" hoặc "mã hợp lệ". Mã của bạn được định dạng tốt nhưng có hành vi không xác định, một số người dường như gọi đó là "không hợp lệ". Điểm của bạn là viết tắt: mặc dù: đó là một điều ngu ngốc mà bạn có thể làm với một giá trị const, nhưng không thể dễ dàng làm với một rvalue. Một thủ thuật tương tự làm việc với 'this' là' template T & stupid (const T & r) {return const_cast (r);} 'theo sau bởi' stupid (this) = 0; '. Không được khuyến khích. –

+0

+1 Hmm, vì vậy các mẫu là thứ chưa được thực hiện dễ dàng. :) –

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