Bạn muốn sử dụng mã có tính chất này trong trường hợp nào trong c ++?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Bạn muốn sử dụng mã có tính chất này trong trường hợp nào trong c ++?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
Câu trả lời:
Bạn sẽ muốn chuyển một con trỏ bằng tham chiếu nếu bạn cần sửa đổi con trỏ chứ không phải đối tượng mà con trỏ đang trỏ tới.
Điều này tương tự như lý do tại sao con trỏ kép được sử dụng; sử dụng tham chiếu đến con trỏ an toàn hơn một chút so với sử dụng con trỏ.
delete
hoặc gắn con trỏ đó vào một số vị trí khác trong bộ nhớ? Hay tôi đã hiểu sai?
[]
nhà điều hành. Một chữ ký có thể (và trên thực tế là tự nhiên) cho điều này sẽ là const T &operator[](size_t index) const
. Nhưng bạn cũng có thể có T &operator[](size_t index)
. Bạn có thể có cả hai cùng một lúc. Sau này sẽ cho phép bạn làm những việc như thế myArray[jj] = 42
. Đồng thời, bạn không cung cấp một con trỏ tới dữ liệu của mình, vì vậy người gọi không thể làm xáo trộn bộ nhớ (ví dụ: vô tình xóa nó).
50% lập trình viên C ++ muốn đặt con trỏ của họ thành null sau khi xóa:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
Nếu không có tham chiếu, bạn sẽ chỉ thay đổi bản sao cục bộ của con trỏ, không ảnh hưởng đến người gọi.
paranoid_delete
, nhưng Puppy đã đổi tên nó thành moronic_delete
. Anh ta có lẽ thuộc về 50% còn lại;) Dù sao, câu trả lời ngắn gọn là con trỏ cài đặt đến null sau delete
hầu như không bao giờ hữu ích (vì dù sao thì chúng cũng nằm ngoài phạm vi) và thường cản trở việc phát hiện các lỗi "sử dụng sau khi miễn phí".
delete
là ngu ngốc. Puppy, tôi đã thực hiện một số googling, tôi không thể hiểu tại sao xóa hoàn toàn vô dụng (có lẽ tôi cũng là một googler khủng khiếp;)). Bạn có thể giải thích thêm một chút hoặc cung cấp một liên kết?
Câu trả lời của David là đúng, nhưng nếu nó vẫn còn hơi trừu tượng, đây là hai ví dụ:
Bạn có thể muốn bằng không tất cả các con trỏ giải phóng để bắt các sự cố bộ nhớ sớm hơn. C-style bạn sẽ làm:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
Trong C ++ để làm điều tương tự, bạn có thể làm:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
Khi xử lý danh sách liên kết - thường được biểu diễn đơn giản dưới dạng con trỏ đến nút tiếp theo:
struct Node
{
value_t value;
Node* next;
};
Trong trường hợp này, khi bạn chèn vào danh sách trống, bạn nhất thiết phải thay đổi con trỏ đến vì kết quả không phải là NULL
con trỏ nữa. Đây là trường hợp bạn sửa đổi con trỏ bên ngoài từ một hàm, vì vậy nó sẽ có tham chiếu đến con trỏ trong chữ ký của nó:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
Có một ví dụ trong câu hỏi này .
Tôi đã phải sử dụng mã như thế này để cung cấp các chức năng cấp phát bộ nhớ cho một con trỏ được truyền vào và trả về kích thước của nó vì công ty của tôi "đối tượng" với tôi bằng cách sử dụng STL
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
Nó không đẹp, nhưng con trỏ phải được truyền bằng tham chiếu (hoặc sử dụng con trỏ kép). Nếu không, bộ nhớ được cấp phát cho bản sao cục bộ của con trỏ nếu nó được truyền theo giá trị dẫn đến rò rỉ bộ nhớ.
Một ví dụ là khi bạn viết một hàm phân tích cú pháp và chuyển cho nó một con trỏ nguồn để đọc từ đó, nếu hàm được cho là đẩy con trỏ đó về phía trước phía sau ký tự cuối cùng đã được trình phân tích cú pháp nhận dạng chính xác. Việc sử dụng một tham chiếu đến một con trỏ sẽ làm rõ ràng rằng sau đó hàm sẽ di chuyển con trỏ ban đầu để cập nhật vị trí của nó.
Nói chung, bạn sử dụng tham chiếu đến con trỏ nếu bạn muốn chuyển con trỏ đến một hàm và để nó di chuyển con trỏ gốc đó đến một số vị trí khác thay vì chỉ di chuyển một bản sao của nó mà không ảnh hưởng đến bản gốc.
Một tình huống khác khi bạn có thể cần điều này là nếu bạn có bộ sưu tập con trỏ stl và muốn thay đổi chúng bằng thuật toán stl. Ví dụ về for_each trong c ++ 98.
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
Ngược lại, nếu bạn sử dụng chữ ký changeObject (Object * item), bạn có bản sao của con trỏ, không phải bản gốc.