2009-10-15 21 views
6

Tôi có một chỗ trong mã mà thường nóiC++: cách đối phó với đối tượng const cần được sửa đổi?

const myType & myVar = someMethod(); 

Vấn đề là:

  • someMethod() trả về const myType

  • tôi cần để có thể thay đổi myVar sau này, bằng cách gán giá trị mặc định nếu đối tượng ở trạng thái không hợp lệ. Vì vậy, tôi cần phải thực hiện myVar để không phải là const.

    1. Tôi cho rằng tôi cần phải thực hiện myVar cũng không được tham chiếu, phải không? Ví dụ. myType myVar?

    2. Cách C++ "chính xác" để thực hiện điều này từ const-to-nonconst là gì? Tĩnh đúc? Lexical cast? Thứ gì khác?

Tôi có thể truy cập để cast từ vựng tăng, vì vậy tôi không nhớ tùy chọn đó, nhưng tôi muốn các phi giải pháp tăng cũng như nếu nó kết thúc tôi không được phép sử dụng tăng.

Cảm ơn!

+0

Chức năng ban đầu có trả lại 'const myType' hoặc' const myType & 'không? –

+0

'const myType' Tôi nghĩ rằng –

+2

@Lou Franco: Xin lỗi, nhưng điều đó không đúng. Mã trong bài đăng gốc là một ví dụ về sách giáo khoa về tình huống, điều này làm cho toàn bộ thời gian tạm thời được mở rộng để phù hợp với thời gian tồn tại của tham chiếu. Không, tạm thời không bị phá hủy ở đây. – AnT

Trả lời

5

Tôi sẽ không sử dụng các giải pháp const_cast và việc sao chép đối tượng có thể không hoạt động. Thay vào đó, tại sao không gán điều kiện cho tham chiếu const khác? Nếu myVar hợp lệ, hãy gán nó. Nếu không, hãy gán mặc định. Sau đó, mã bên dưới có thể sử dụng tham chiếu const mới này. Một cách để làm điều này là sử dụng các biểu thức điều kiện:

const myType& myOtherVar = (myVar.isValid() ? myVar : defaultVar); 

Một cách khác là viết một hàm mang theo một tham chiếu const (myVar) và trả về một trong hai myVar hoặc defaultVar, tùy thuộc vào giá trị của myVar, và gán giá trị trả về từ đó đến myOtherVar.

Cách thứ ba là sử dụng con trỏ const, trỏ nó tại địa chỉ myVar hoặc địa chỉ của đối tượng mặc định.

+0

Yay. Những công việc này. –

1
const_cast<type without const>() 

Nhưng, không someMethod() thực sự trả lại const myType? Nếu vậy, bạn đang thực hiện một tham chiếu đến một tạm thời - nó sẽ bị phá hủy và tham chiếu của bạn sẽ là xấu. Thay đổi myVar thành không-ref (sao cho bản sao) - không cần khai báo nó trong trường hợp đó. Hoặc, nếu someMethod() trả về một tham chiếu, hãy sử dụng const_cast nếu bạn phải (nhưng bạn đang thay đổi một cái gì đó mà someMethod suy nghĩ sẽ không thay đổi).

0

Hãy thử như sau

myType& mutableMyVar = const_cast<myType&>(myVar); 

Nói chung const loại bỏ là một ý tưởng tồi mặc dù. Phương thức người gọi trả về cho bạn một tham chiếu đến một biến mà nó tin rằng sẽ được coi là const. Nếu bạn vi phạm giả định này bằng cách loại bỏ const và sửa đổi biến bạn có thể đặt một trong hai đối tượng vào trạng thái hợp lệ.

Điều này có thể hợp pháp trong trường hợp cụ thể của bạn nhưng nói chung đây là điều cần tránh

+0

Nếu nó được tránh, tại sao cung cấp nó như là một câu trả lời ??? – hasen

+0

@ hasen j, vì đây là cấu trúc hợp lệ đôi khi cần thiết. Nói chung để tránh nhưng đôi khi không có sự lựa chọn nào khác ngoài việc làm điều đó. – JaredPar

+0

Không. Điều này thật tệ đến mức nguy hiểm. Nếu là một tham chiếu const được trả về sau đó sửa đổi nó dẫn đến hành vi không xác định. Nếu nó đang được sao chép trở lại (và do đó tạm thời) thì tuổi thọ của đối tượng không còn được mở rộng và đối tượng bị phá hủy tại tuyên bố. Do đó dẫn đến hành vi không xác định. –

9

Bạn có thể không cần bất kỳ dàn diễn viên nào. Nếu bạn có thể sao chép số T, thì bạn cũng có thể sao chép T const, các trường hợp bệnh lý bị loại trừ. Bản sao của số T const không cần phải là bản thân số T const.

myType myVar = someMethod(); // Creates a non-const copy that you may change. 
+1

Điều này sẽ gọi các nhà xây dựng bản sao nó sẽ không? Sau đó, V_D_R sẽ không làm việc với một tham chiếu đến đối tượng được trả về bởi someMethod mà là một bản sao của nó. – theycallmemorty

+1

someMethod trở lại là gì? Nó có thể là tạm thời, vì vậy để giữ nó xung quanh nó cần phải được sao chép ở đâu đó. –

+0

@theycallmemorty: Áp phích gốc đã cho biết rằng đối tượng được trả về * theo giá trị *, không phải bằng tham chiếu. Thực tế là đối tượng đã được trả về từ hàm theo giá trị (nếu áp phích gốc là đúng) immedaitely có nghĩa là sao chép đối tượng đó là một điều được chấp nhận đúng đắn để thực hiện. – AnT

0

Bạn có thể tạo một đối tượng từ đối tượng const sử dụng bản sao constructor hoặc điều hành một cái gì đó phân công và sau đó sửa đổi nó.

Nhưng tôi nghĩ bạn sẽ thấy rõ hơn lý do tại sao hàm này trả về loại const ngay từ đầu. Sẽ có một lý do tại sao nó được tuyên bố là const.Nếu bạn đang rất chắc chắn rằng đó là những gì bạn muốn, bạn luôn có thể const_cast đi constness như thế này:

T obj1 = const_cast<T&> (obj); 
0

là gì C++ cách "đúng" làm const-to-nonconst này? Tĩnh đúc? Lexical cast? Thứ gì khác?

Không có cách nào C++. Vì một lý do nào đó, tác giả của lớp đó đã quyết định rằng bạn không thể sửa đổi cá thể thông qua phương thức này.

Nếu bạn là tác giả, bạn có thể làm cho nó trở về tham chiếu không phải là const. Nhưng những điều đó vẫn còn đáng ngờ, trừ khi lớp học thực sự không ẩn doanh nghiệp của bạn (ví dụ: vector không ẩn những gì nó giữ cho bạn và chỉ ẩn cách nó giữ nội dung cho bạn).

Một cách tốt hơn (tùy thuộc vào điều này là gì) cũng có thể không để lộ thành viên cho thao tác bên ngoài, mà là cung cấp phương pháp thao tác này cho bạn. Ví dụ:

class BadPosition 
{ 
    int x, y; 
public: 
    int& get_x() { return x; } 
    int& get_y() { return x; } 
    //... 
}; 

BadPosition p; 
p.get_x() += 1; 
p.get_y() += -1; 

class BetterPosition 
{ 
    int x, y; 
public: 
    void move(int x_inc, int y_inc) { x += x_inc; y += y_inc; } 
    //... 
}; 

BetterPosition p; 
p.move(1, -1); 

Nếu bạn cần điều này để đặt lớp ở trạng thái hợp lệ sau đó, có thể xem xét làm cho hàm tạo của nó làm điều đó. Nếu bạn không thể làm điều đó, ít nhất là cung cấp một phương thức Init(), để không làm cho một lớp phức tạp như vậy hoàn toàn dựa vào việc bị thao tác bên ngoài vào một cái gì đó có thể sử dụng được. Có thể dĩ nhiên bạn có thể tạo một bản sao, sửa đổi và sau đó sử dụng bản sao sửa đổi để thay thế toàn bộ bản sao bằng một bản khác (giả sử điều này là đủ để xây dựng nó):

X x; 
... 
Y y = x.get(); 
y.modify(); 
x = X(y); 

Edit: Vì vậy, lợi nhuận lớp bằng giá trị? Trong trường hợp này không nên có cách nào để sửa đổi cá thể trong lớp, vì tất cả những gì bạn nhận được là một bản sao ngay từ đầu. Bạn có thể tham chiếu với tham chiếu const, nhưng ngay cả khi bạn bỏ đi constness từ tham chiếu đó, bạn vẫn đang tham chiếu tạm thời.

Câu trả lời của tôi ở trên giả định nó trả về tham chiếu const, vì điều đó có vẻ hợp lý hơn (tôi chưa thấy mọi người thường trả về giá trị const, mặc dù có thể có những người khuyên bạn nên sử dụng nó).

1

Không có cách nào "C++" (không chỉ cho điều này, mà còn cho bất kỳ thứ gì).

Cách xấu là sử dụng const_cast, nhưng hành vi sẽ không được xác định (đọc: đừng làm điều đó).

Điều bạn cần làm là sao chép đối tượng và sau đó sửa đổi bản sao. Đó là cách duy nhất thích hợp để xử lý các đối tượng không thay đổi được.

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