2013-08-14 65 views
10
class C{ 
    //methods and properties 
} 

void C::some_method(C* b){ 
    delete this; 
    this = b;  
} 

này mang lại cho tôi follwing lỗi khi biên dịch:thay đổi 'này' con trỏ của một đối tượng để chỉ đối tượng khác nhau

error: lvalue required as left operand of assignment 

ý định của tôi: Giả sử có những đối tượng a và b của lớp C. nội dung của lớp C có thể rất lớn và trường bằng cách sao chép trường có thể rất tốn kém. Tôi muốn tất cả nội dung của 'a' được thay thế bởi b một cách kinh tế.

Trình tạo bản sao mặc định có thực hiện tác vụ dự định không?

tôi tìm thấy một cái gì đó gọi là 'di chuyển constructor' http://akrzemi1.wordpress.com/2011/08/11/move-constructor/

Có lẽ, nó có thể nhận được hiệu quả mà tôi muốn.

+0

bạn có chắc chắn bạn có thể làm điều gì đó như thế này không ?? – DonCallisto

+15

Vì vậy, nó có. Bạn vừa phát hiện ra rằng 'điều này' không thể gán lại được bởi vì * điều đó sẽ không có ý nghĩa gì cả *. Bạn có câu hỏi nào không? Không thể thay đổi –

+0

'this'. Mục tiêu cấp cao hơn bạn đang cố gắng đạt được là gì? –

Trả lời

12

Con trỏ this là một con trỏ ẩn đối tượng trong ngữ cảnh mà bạn đang làm việc, bạn không thể gán lại nó.

Theo kinh thánh Stroustrup của (C++ Ngôn ngữ lập trình, 3rd edition Tôi có) this được thể hiện như

C * const this 

có nghĩa là bạn có một liên tục trỏ đến lớp học của bạn C, do đó trình biên dịch sẽ phàn nàn nếu bạn cố gắng thay đổi nó.

EDIT:

Như tôi đã được sửa chữa, khái niệm nêu trên không mô tả this hoàn toàn chính xác, cho this thực sự là một rvalue.

+0

Tôi không chắc chắn nếu 'this' là const, cảm ơn cho thông tin. – EarlGrey

+0

Bạn thậm chí có thể đi trên đầu trang của điều này và có một 'this'-con trỏ đến một đối tượng liên tục, năng suất' const C * const này ' –

+1

Trích dẫn nói nó được "thực hiện" như thế nào. Chính thức, 'this' không phải là một đối tượng; nó là một biểu thức giá trị. –

15

Bạn không thể thay đổi những gì this trỏ đến. Tôi cũng sẽ không biết tại sao bạn muốn làm điều này.

+1

@ kol Thực ra bạn không thể, trừ khi trình biên dịch của bạn bị hỏng nghiêm trọng (hoặc nghiêm túc cũ --- bạn có thể lên đến một chút trước năm 1990, khi khả năng quá tải 'toán tử mới' được thêm vào ngôn ngữ). –

6

Bạn không thể chỉ định giá trị khác cho this vì nó trỏ đến chính đối tượng và điều này không có ý nghĩa gì. Bạn có thể khởi tạo một đối tượng mới và thay vào đó sử dụng con trỏ của nó.

Hơn nữa, nếu bạn cố gắng để tạo ra một bản sao của đối tượng, bạn có thể ghi đè lên operator=

class Foo 
{ 
    public: 
    [...] 
    Foo& operator=(const Foo& foo); 
} 

int main() 
{ 
Foo foo; 
foobar = foo; //invoke operator= overwrited method 
} 


1

Các lỗi nói: "Bạn không thể gán b để this". Theo như tôi biết, this là thứ bạn không thể thay đổi, bởi vì nó không phải là một con trỏ thực tế, mà là một tham chiếu tự.

+0

Đó là một con trỏ, về cơ bản là 'ClassType * const this', có nghĩa là nó không thể được sửa đổi để trỏ đến một cái gì đó khác, và vì nó là một giá trị, nó không thể nằm trên các biểu thức của một biểu thức. – Rapptz

+1

@Rapptz Nó có một kiểu con trỏ, nhưng nó _isn't_ const, vì nó là một rvalue, và rvalues ​​của loại non-class không có cv-qualifiers. –

+0

Ví dụ khác về giá trị của loại không thuộc loại là gì? –

14

Để trích dẫn tiêu chuẩn:

Trong cơ thể của một hàm thành viên không tĩnh (9,3), từ khóa this là một biểu prvalue có giá trị là địa chỉ của đối tượng mà chức năng được gọi là.

"Giá trị" là giá trị thuần túy, chẳng hạn như 42 hoặc 3.14159. Cũng giống như cách bạn không thể làm điều gì đó như 42 = x, bạn không thể gán cho this; trong cả hai trường hợp (ít nhất là khái niệm), có không có đối tượng có giá trị có thể thay đổi.

Và tôi thực sự tò mò như những gì bạn mong đợi để xảy ra nếu tôi viết một cái gì đó như:

int 
main() 
{ 
    C c1; 
    C c2 
    c1.some_method(&c2); 
} 

Bạn có mong đợi địa chỉ của c1 để bằng cách nào đó một cách kỳ diệu thay đổi, và cho c1c2 để là bí danh cho cùng một đối tượng? (Và c1.some_method(NULL) là intreguing thậm chí nhiều hơn.)

+2

@ kol Trên thực tế, bạn không thể, và câu trả lời của bạn chỉ đơn giản là không chính xác. Tiêu chuẩn này khá rõ ràng ở đây: 'this' là một giá trị (hoặc một rvalue trong pre-C++ 11), và gán cho một rvalue là bất hợp pháp, và có _no_ cách để có được một lvalue từ một rvalue của non-class kiểu. –

+0

@JamesKanze Có, tôi muốn chúng là bí danh. –

+0

@UtkristAdhikari Nhưng điều đó hiển nhiên là không thể, vì mã trong một hàm thành viên không thể thay đổi ý nghĩa của một biểu tượng trong 'main'. Trong 'main',' c1' chỉ định một thực thể rất cụ thể, và biểu tượng kết hợp -> thực thể được quản lý hoàn toàn bởi trình biên dịch và trình liên kết, tại thời gian biên dịch và liên kết. –

0

Chỉ cần sử dụng các phương pháp thông thường thay vì ma thuật đen và UB:

C* c1 = new C(); 
C* c2 = new C(); 

// do some work perhaps ... 

delete c1; 
c1 = c2; 

Bây giờ c1 là một bí danh cho c2 như bạn muốn. Hãy cẩn thận mặc dù khi làm sạch bộ nhớ, do đó bạn không kết thúc xóa một đối tượng hai lần. Bạn có thể xem xét các con trỏ thông minh ...

+0

nhiệm vụ phải xảy ra bên trong phương thức c1 –

+0

Mã này không phải là cách tiếp cận thông thường cho bất cứ điều gì. Nếu bạn chỉ muốn c1 trỏ đến cùng một đối tượng như c2, không có lý do gì để xóa mới một đối tượng cho c1. Chỉ cần gán c2 đến c1 ngay lập tức. Hơn nữa, thường mới và xóa không phải là ngoại lệ an toàn (ngoại lệ an toàn là quan trọng ngay cả khi bạn không sử dụng cơ chế xử lý ngoại lệ tích hợp C++). Ít nhất, sử dụng một unique_ptr để giữ đối tượng được cấp phát động của bạn. Nhưng trừ khi bạn có lý do chính đáng, bạn không nên phân bổ động ở địa điểm đầu tiên. Cách tiếp cận thông thường để tạo bí danh là thông qua tham chiếu. – suncho

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