Skip to content

Tweak "Raw pointers (C++)" topic #5574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions docs/cpp/raw-pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ A pointer can also be *dereferenced* to retrieve the value of the object that it
int j = *p; // dereference p to retrieve the value at its address
```

A pointer can point to a typed object or to **`void`**. When a program allocates an object on the [heap](https://wikipedia.org/wiki/Heap) in memory, it receives the address of that object in the form of a pointer. Such pointers are called *owning pointers*. An owning pointer (or a copy of it) must be used to explicitly free the heap-allocated object when it's no longer needed. Failure to free the memory results in a *memory leak*, and renders that memory location unavailable to any other program on the machine. Memory allocated using **`new`** must be freed by using **`delete`** (or **`delete[]`**). For more information, see [`new` and `delete` operators](new-and-delete-operators.md).
A pointer can point to a typed object or to **`void`**. When a program allocates an object on the [heap](https://wikipedia.org/wiki/Heap) in memory, it receives the address of that object in the form of a pointer. Such pointers are called *owning pointers*. An owning pointer (or a copy of it) must be used to explicitly free the heap-allocated object when it's no longer needed. Failure to free the memory results in a *memory leak*, and renders that memory location unavailable to any other program on the machine. Memory allocated with **`new`** must be freed using **`delete`**, and memory allocated with **`new[]`** must be freed using **`delete[]`**. For more information, see [`new` and `delete` operators](new-and-delete-operators.md).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory allocated using new must be freed by using delete (or delete[]).

This implies delete[] can be used in place of delete, which is wrong. Hence, this sentence is extended to make it explicit that new must be matched with delete, and new[] must be matched with delete[].


```cpp
MyClass* mc = new MyClass(); // allocate object on the heap
Expand Down Expand Up @@ -78,7 +78,7 @@ void func_B(MyClass mc)
// This statement modifies only the local copy of mc.
mc.num = 21;
std::cout << "Local copy of mc:";
mc.print(); // "Erika, 21"
mc.print(); // "Erika:21"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output comments used the wrong delimiter (", " instead of the correct ":"). All subsequent occurrences are fixed.

}

int main()
Expand All @@ -99,28 +99,28 @@ int main()
MyClass* pcopy = &mc;

// Use the -> operator to access the object's public members
pmc->print(); // "Nick, 108"
pmc->print(); // "Nick:108"

// Copy the pointer. Now pmc and pmc2 point to same object!
MyClass* pmc2 = pmc;

// Use copied pointer to modify the original object
pmc2->name = "Erika";
pmc->print(); // "Erika, 108"
pmc2->print(); // "Erika, 108"
pmc->print(); // "Erika:108"
pmc2->print(); // "Erika:108"

// Pass the pointer to a function.
func_A(pmc);
pmc->print(); // "Erika, 3"
pmc2->print(); // "Erika, 3"
pmc->print(); // "Erika:3"
pmc2->print(); // "Erika:3"

// Dereference the pointer and pass a copy
// of the pointed-to object to a function
func_B(*pmc);
pmc->print(); // "Erika, 3" (original not modified by function)
pmc->print(); // "Erika:3" (original not modified by function)

delete(pmc); // don't forget to give memory back to operating system!
// delete(pmc2); //crash! memory location was already deleted
delete pmc; // don't forget to give memory back to operating system!
// delete pmc2; //crash! memory location was already deleted
Comment on lines +122 to +123
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer the more idiomatic delete expr; over delete(expr);, even though the latter technically works. As an aside, found this interesting comment at c++ - Is there any difference between delete x and delete(x)? - Stack Overflow.

}
```

Expand Down Expand Up @@ -156,7 +156,11 @@ int main()
}
```

Certain arithmetic operations can be used on non-`const` pointers to make them point to another memory location. Pointers are incremented and decremented using the **`++`**, **`+=`**, **`-=`** and **`--`** operators. This technique can be used in arrays and is especially useful in buffers of untyped data. A `void*` gets incremented by the size of a **`char`** (1 byte). A typed pointer gets incremented by size of the type it points to.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A void* gets incremented by the size of a char (1 byte).

This implies that pointer arithmetic can be done on void*, but that causes a hard error, since it is non-standard and only available as an extension on GCC (not sure if this extension exists for MSVC). Hence, this sentence is removed, but we can consider explicitly stating that it is not allowed.

```Output
1 2 3 4 5
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a trailing space here as that's the verbatim output of this snippet.

```

Certain arithmetic operations can be used on non-`const` pointers to make them point to another memory location. Pointers are incremented and decremented using the **`++`**, **`+=`**, **`-=`** and **`--`** operators. This technique can be used in arrays and is especially useful in buffers of untyped data. A typed pointer gets incremented by size of the type it points to.

The following example demonstrates how pointer arithmetic can be used to access individual pixels in a bitmap on Windows. Note the use of **`new`** and **`delete`**, and the dereference operator.

Expand Down Expand Up @@ -264,7 +268,7 @@ int main()
void* p = static_cast<void*>(mc);
MyClass* mc2 = static_cast<MyClass*>(p);
std::cout << mc2->name << std::endl; // "Marian"
delete(mc);
delete mc;

// use operator new to allocate untyped memory block
void* pvoid = operator new(1000);
Expand Down Expand Up @@ -332,6 +336,11 @@ int main()
}
```

```Output
hello world from MSVC
Good morning and hello world from MSVC
```

## See also

[Smart pointers](smart-pointers-modern-cpp.md)\
Expand Down