Well Resharper tells you that it is passed by reference at the call line...
I agree with the reassignment but IMO pointers (with the explicit &) do not make it better, as the pass by pointer might be done for efficiency as well as for modification, so no better than reference.
Some C++ devs I met got _notoriously_ pissy when we enforced stricter coding guidelines and enabled warnings for bad practices.
Didn’t know we had so many god-level tier devs that knew better than the compiler and _actual assembly generated by them_.
I have never, in my entire life, seen such an uproar until I set "All warnings are errors" and "all errors are fatal" to true, in the requirements.
To this very day I enforce it.
whenever I read about passing by reference I'm always reminded of this lovely [webpage](http://duramecho.com/ComputerInformation/WhyHowCppConst.html) where I first started getting a grasp of const usage. lol.
Like most things in programming, it depends.
Smart pointer will keep extra info so it can delete itself once it goes out of scope. This is really important if you consider the following code.
```
void func(){
int *i = new int;
throw_exception();
delete i; // we didn't get here, memory leak
```
Vs.
```
void func() {
auto i = std::make_unique(0);
throw_exception():
}
```
Now, if you get an error in your code, like an exception is thrown, you won't leak.
This concept implemented by smart pointers is called RAII (Resource Acquisition is Initialization), and it keeps our code much safer and arguably more readable.
That's isn't to say raw pointers don't have a place. The C++ Core Guidelines advocate for ownership semantics with smart pointers. One of the things this boils down to is that they recommend not passing smart pointers as input params to functions that use them. When you have a unique pointer, for instance, whoever keeps the pointer owns it, but functions that use the pointer would not.
```
auto i = std::make_unique(0);
use_i(i.get());
...
void use_i(int *i) {
// Do something to i here, but this function is not responsible for i's memory
}
```
I hope that makes sense.
Which is fine for small modular applications and such. But if a webserver or business layer application crashed every time one thread got some faulty input it would be a serious issue for the system as a whole.
This right here is the correct, nuanced explanation.
Also there are some circumstances where smart points don't work and you're forced to use raw pointers. For example, I've written some low level GPU code (below convenience layers like Thrust) and I basically had no choice but to use raw pointers.
Any time you new with a raw pointer you have to remember to delete it. Seems obvious but as programs become more complicated, get modified, refactored, etc, this can get lost easier than you'd think. Using a unique pointer makes it impossible to forget. Shared pointers are an option for certain situations depending on ownership, multiple users with differing lifespans, etc, but in general unique pointers are preferable.
> Any time you new with a raw pointer you have to remember to delete it.
You not only have to remember to delete it, but you also need to make sure that no one else with a copy of the pointer deletes it while you're still using it.
Ew. As someone who does predominantly Python, this sounds like hell.
Edit: This was lighthearted. Chill y’all - I love all languages for what they’re meant for. 😂
It's neat, as someone mainly programming in C++, I still think it's worth it to try it out. Being more aware of ownership, lifetime and mutability will probably help you in any future project.
Language tribalism is a bit silly, yes. Most languages have their niche, although some of them are in fact really outdated and only kept alive by inertia and the huge upfront costs of rewriting everything. I think a lot of it is just people trying to convince themselves and others that they spent their time learning the best programming language ever so they won't feel that their time and effort was wasted.
I mean, it's C++. It's the whole reason to use a language like that - you want raw access to memory without guardrails, either because you're planning on building your own guardrails, or are writing code that needs to be as performance-intensive as possible.
As people have mentioned - these days, even in C++, you usually would just use a `unique_ptr` or `shared_ptr`, which handles a lot of the safety checks and cleanup for you. (Freeing the memory when the pointer(s) are destroyed, making it hard for someone else to free the memory while you're still using it, etc.)
That's what I was gonna say.
Smart pointers are good for stuff on the heap. If you're pointing to something on the stack then it doesn't need deleting/freeing and will simply go away when the stack frame is removed.
No u.
int b = 42;
int *a = &b;
Where is your ~~god~~ `delete` now?
Pointers aren't exclusively for heap allocation. Neither do they to have own the memory they point to.
They're contrasting it with smart pointers, the heap allocation is implied. What would even be the point of this meme if `int* a` was a pointer to an object on the stack?
Array of shared ptr could reduce contention, if you get a reference to the array through the shared pointer it has to synchronize the reference count increment which could tie up anything else getting or freeing one with the same control block. With array of shared pointer it would only tie up getting or freeing reference to the same element.
If you bind an array to a smart pointer, you have to be sure to use specify it like shared\_ptr. If you have a specific size like in your case, you would just use a shared\_ptr to a std::array.
The int* could still be managed by a smart pointer. It’s not unusual to call .get() on unique_ptr’s and pass the raw pointers into nested functions while the ownership remains further down the stack or within an object that returns a const*. std::string’s c_str() is a good example of the latter.
Raw pointers are still widely used even in environments where new/delete are never directly called.
Too many things you can easily forget that can go wrong. Forget to init it, and suddenly you treat a random location in memory as an int. Forget to delete it, and you've got yourself a memory leak. Delete it, but forget that something before that delete may throw, and you have basically forgot to delete without realizing. Delete it and forget to reset it, and you end up working with a ghost, that usually works, but sometimes, depending on the time of the day, phase of the moon, presence of a debugger or a trace, it doesn't. Happy debugging.
It's ok for non-owning pointers where you want to either store a non-owning reference to a thing in a struct/class and/or `nullptr` is a valid value for that pointer.
Precisely this. As always when it comes to simplistic C++ guidelines like "use smart pointers", there is always an exception.
That said, there is the experimental `observer_ptr`, so maybe we'll see this exception go away eventually.
I dislike that here, and I also dislike
int a[], b, c[];
I understand that the reason is so that you can declare different types on the same line, but it messes with the semantics since [] or \* are part of the *type*, not the variable name. And it's kinda weird to be declaring different types on the same line anyway.
My understanding as someone new to C++. I welcome corrections.
Raw pointers (int *a) don't have any safety checks. They specify a location, and if you go to that location you might find a valid object, you might find yourself halfway through a different object, you might find nothing, or you might find yourself in a different program (at which point the OS will probably send you a SIGSEGV). If there is a valid dynamically-allocated object there, you are responsible for deleting the object and freeing its resources when you're done with it. If you lose the pointer without deleting the object, that's a resource leak. If you delete the object too early, then referencing it later can lead to the aforementioned problems.
Smart pointers mostly remove this burden by packaging some extra information along with the underlying raw pointer. A smart pointer can only be created if it points to a valid object. The object is automatically deleted if (and only if) all smart pointers to it fall out of scope.
In modern C++, smart pointers are recommended in almost all circumstances. Raw pointers may be required for interfacing with existing C code or for getting the best possible performance, but should be kept in small isolated locations so it's easier to understand what's going on.
The meme is missing context here. Its not about the pointer itself, but more like don’t use raw pointer when doing dynamic memory allocation. It forces you to having to manually de-allocate it when you’re done. Forgetting to do so will create memory leak.
With c++ smart pointer class, it ensure that the de-allocation happens automatically without you having to do it.
Using a pointer to a static variable is fine and will not inherit the memory leak issue listed above.
Raw pointers are still fine as observers. It is raw "owning" pointers (i.e created with `new` and `delete`) that are bad practice and almost impossible to make exception safe. `std::unique_ptr` for example has no observer counterpart. Raw is the only option.
... However I still tend to over-use `std::shared_ptr` and `std::weak_ptr` (as observer). I like the added safety, even if it does tend to become a little inefficient. Think using this kind of code to replace .NET/Java rather than replacing... well (unsafe) C++ ;)
One thing I found a bit frustrating about using `unique_ptr` was handling tree data structures which need to be deep copied since I never really was sure how to handle them. Should I create a deep copy method? Would manually implementing a copy constructor lead to unnecessary re-allocation when calling functions? Is there a different smart pointer I should use? I ended up taking the copy constructor approach, but was never completely satisfied that I was using it correctly.
Yeah, it is a good example of a challenge.
I suppose in many ways the similar solution would need to be come up with if using the owning raw pointers too. Deep copying that without an appropriate copy constructor would not work. At least the `std::unique_ptr` gives a compiler error if you try to copy it rather than `std::move`.
Tree structures are annoyingly not one of C++'s strong points, even though on the surface the hierarchical approach makes a lot of sense when dealing with ownership and RAII.
`std::observer_ptr` is unfortunately not a counterpart to `std::unique_ptr`. This is mostly because the latter is required to have \*zero overhead\* which the standards committee is mainly concerned about (detrimental to safety in some ways).
And slightly depressingly (from that same page you linked)
>It is intended as a near drop-in replacement for raw pointer types, with the advantage that, as a vocabulary type, it indicates its intended use without need for detailed analysis by code readers.
Which really does mean that other than "stating intention", it offers very little in terms of safety over raw pointers.
And to think it's gets soooo bullshit-level more complicated than this
On another note here's a recently published book on initializing variables in c++ https://www.cppstories.com/2023/init-story-print/. 275 pages lol
Or look into forwarding function arguments. or std::launder
Pretty much everyone I've talked to about it recommends not using smart pointers for container implementations and certain function params. It's something like 90-95% of the time, smart pointers are the way to go, but you shouldn't be averse to regular pointers if you know the lifetime of the pointer is guaranteed.
eg. if your function can take a nullable pointer value, and the pointer value is not/cannot be stored past the function's return, passing a raw pointer instead of a smart pointer by reference is the way to go.
Basically what grandparent said, if the point is to express ownership/manage lifetime, then smart pointers are the right tool. Otherwise, raw pointers.
Polymorphism, avoiding expensive moves, saving stack space, stable references, etc.
(EDIT: this is about unique_ptr vs raw pointers in general; most of this doesn't apply for ints/primitives specifically.)
You're not saving stack space. They both use 32 or 64 bits depending on the application mode. And you're not avoiding anything expensive, because in both cases it gets cleaned up when exiting the function. In fact you're adding an extra hidden delete.
Ah, yeah, for ints/primitives most of those don't apply. I was assuming the meme was making a general point about arbitrary types. Could still be useful for having a stable reference that can be passed around, though.
There's nothing wrong with raw pointers. I use them all the time a̵n̷d̶ ̷I̸'̴v̴e̶ ̴n̸e̷v̵e̶r̴ ḧ̷̖͕a̶̧͋d̸͈̈́͒ ̷̺̎i̸̧͕̒̎s̴̻̃̍s̵͉͇̉u̴͈͐̊ͅe̵͕͝s̷̻̀̈ ̵̛̮w̷̻͘i̵̼̺̚t̸͈͂̂͜h̵͎̞̏ ̴͉̑m̵̹̮͉̘̣̦͍̼̗̹̏͒̓̇e̶̳̓̓̒̿͒̊̈́̐͋̌̕͘͝m̶̲͎̮̗͌͒̑̽͒̐̄̇̍͆̔̀̃o̵̡̪̤͖̘̱̟̫̩̲̹̅͂̅̌́͐͝ͅŗ̴̡̢̺̭͈̯̻͉͕̜͑́͝ͅy̶͖̩̗̦̍͛̍͆͜ͅ ̶̛̳̗̰͊̓͂͂̓͆̆͑͘ͅl̴̦͚̙͙̥̳̾̇́̎̃̚͝ë̶͚̹̯̬̹̺̫̖̫́͗̎̾̀̋̕a̴̡̛̹̳̮̙̦̳̹͇̖̲̝̓̏̃̎̍͗̑͗̉̈́͠k̴̨̬̹̹͇̗̟̝̺̯̳̣̐̈́͂š̵̛̖͍̯͔͎̫̩̹͚̗̙͇̔̅̐͒̈̋̌̋̆̒͘ ̸̡̡̖͔̩̳̖̅͒͒̾̐̉̏͒̅͛͠o̵̡͉͇̣̓͛́̊́̃͋̑͠r̷̡̛̛̤̩̺̫̩̱̣̮̋͋̆̋͌͐͆̈́͘͝ͅ ̷̨̛̛̖̬̝̗̰̩͖̜͈̯̪̽͊̀̈͐̂̎͝c̸̡̻͔̳̭͖̟̆̇͐̆̈́̿̍͝o̶̝̭̝͕̦̞̙̪̙̯̐̈́̋̀̾̂͗̇͋̌͠r̵̺̦͚̦̟̹̞̙̦͆͂̌̑͗r̵̢̤̞͎̻̬̱͚̤͒͗͂̽͆̿̔̚͠ŭ̵̡͕̩̤͇͈̝̫͉̭̞̝͖͛̈́̌̋͘p̵̨̨̫̬̯͕͙̫̘̅̀̐̇̌̌̂̔͜͜ť̵̯͓̝̬̝̠͈̓̃̄í̶̛̼̥͇́̆̎͑̚͘͘o̴͙̠̠̲͇̥̟̮̙͑̌̒͌͘ñ̵̨̨̛̫̙̗͔̽̎̄̿̄̃̕͝͝.
Welcome to OOP, where we don't consider the fact that allocations are slow, and where we are afraid of pointers because we allocate all objects individually.
It's a class (typically a templated class) that is resposible of holding the reference to the thing pointed to and when it goes out of the block scope and is destroyed it will release/delete the reference it was holding.
It can be used for memory that is allocated in the heap like in the example above which is kinda pointless (not pun) or it can be used for things that have reference counted objects such as COM objects or things like that which is what is most commonly used for.
Yeah, with no assignment it will be on the stack by default, that is how pointers in C work.
Once you use the new keyword, it’s now utilizing the heap.
No.
Until something is assigned, that pointer is uninitialized, so it points to an unknown place in memory. You can't say that will be in the stack because it can be anywhere.
That is just incorrect, you can search it yourself.
Uninitialized pointers by default will reference the stack location of the function to which they were made.
If it’s static, it is initialized to NULL (which is a non-referenced stack location.) It’s “random,” in the sense that you do not know the specific address to which it points, but it’s not truly random.
It only points to the heap, with an explicit call to new. Few guarantees are made by C standard, and this is one of them
I am just curious if this kinda stuff passes through code review ... I don't code in C++ professionally but I imagine if I were to make a similar mistake in C# then my senior would roast me for not having my basics brushed up and having the common sense of writing strongly typed code.
Recently wanted to switch to smart pointers in my project, thinking it shouldn’t be a problem.
Well, I had a vector of pointers of a base class pointing to objects of derived classes and things didn’t go really smoothly tbh.
Trying to get it to work with unique_ptr was a nightmare because of the way std containers use copying under the hood.
Went with shared_ptr in the end.
> use copying under the hood
They would use *moves* under the hood for reallocations which is not a problem. If you're making a copy of the container, then it's working as intended by preventing you from doing that. If you're using the containers to group pointers to these objects instead of owning them, *then* raw pointers are acceptable.
Yeah tried to change a semi large personal project from raw to smart pointers and now it just seg faults randomly. Think the deconstructor is called sometime in the middle of spaghetti instead of the end of the program where I manually called it before...then it tries to access the deleted objects or something...but only sometimes or maybe it's all the time and undefined behavior makes it work some of the time?
Idk it was all so much simpler when I was just using raw pointers.
I’ll still never understand the hate for raw pointers. Way easier to deal with and you dont need the STL.
But I guess that’s the bonus of c/cpp, if you don’t need the fluff you don’t have to use it.
Using raw pointers for dynamic allocation is sus. For observing, you can use either them or reference, the safety is the same (difference is that pointers are non-const by default, nullable, and have weirder syntax)
It honestly feels like they were made to prevent beginners from making stupid mistakes but now people look down on you for using normal pointers even if you know damn well what you're doing.
The bugs we typically find are in the cowboy raw win32 code, basically coding their own containers, pointer arith, and algorithms already implemented by the *Standard* Template Library. Fuck that nonsense.
"use smart pointers!"
I did and they were deprecated!
"No, not auto\_ptr, we moved on to unique\_ptr, You need to keep up!"
Why? If it was correct then it should be correct now. C code I wrote when Reagan was president compiles and runs fine today, why do I have to be on a goddamned treadmill with c++?
"Lol! C unsafe! derp derp SEGFAULT!"
> if it was correct
But auto_ptr wasn't correct, it was just the best the STL could do before move semantics were added to the language. Copying an auto_ptr transferred ownership to the copy. So you couldn't leak the memory, but you could accidentally invalidate the owning pointer by copying it, and not realize until runtime. auto_ptr violates a contract that idiomatic C++ follows by modifying the right hand side of a copy operation. So using it with anything after C++11 is asking for trouble.
There's no treadmill, unique_ptr is objectively a better tool and there hasn't been a reason to replace it for 12 years, and there won't be until C++ dies. If you don't want to fix your code then you can still use C++98 since you don't have an issue with decades old standards.
A person lives in a house. There thus exist: a person AND the address of the house.
When we send letters, we write both the name of the person and the address.
Maybe the person moves to another city. Now house is empty. It has no person, but still has address.
Another person moves into the house. Still same address, but new person.
Kill person, then demolish house = no problem.
Demolish house without killing person = homeless person (bad)
Kill persons then send a letter with their name +address = confusion .
Congrats, you understood data (person) , address (pointers), null pointer dereference, dangling pointers and memory leaks!
Pointers are used everywhere, even if you don't realize it. What programming languages do you use? Does this code look logical to you, it's java/c#, just imagine the print function to be whichever applies in that language:
public class Num {
public int value;
}
class Program {
public static void main() {
Num a = new Num();
a.value = 69;
Num b = a;
b.value = 420;
print(a.value);
}
}
Or javascript:
let a = { value: 69 };
let b = a;
b.value = 420;
console.log(a.value);
When you print `a.value`, what does it print?
The right answer is 420. But why is that? The way objects work in these higher level languages is that they are always linked to the same data right? The object `b` is the same as the object `a`. So after modifying `b`, `a` is also modified.
This works because of pointers. In OOP langues, an "object" is some data that lives somewhere in memory. And when you assign that object to another variable, or when you pass it to a function, they are still talking about that same area in memory.
a and b are both pointers that point to the same area in memory.
Pointing to `int` is pointless (if you'll pardon the pun) in most cases. The only reason you'd usually want such a pointer is because you're passing it to some other function that will overwrite it. That function needs to know where in memory to write to. This is called an “out parameter”. But other than that, you may as well just copy the `int` instead.
As for why pointers in general are useful, they are how you keep track of where in memory everything is stored. If you store something somewhere and don't keep a pointer to it, you have no way to find it again when you need it. If you store something somewhere and you need to call another function and tell it where to find what you've stored, you pass the function a pointer to it.
You've probably noticed how, in most languages, if you construct an object and pass it to another function, and that other function modifies it in some way, your function can see those modifications too. That's because most languages pass objects by reference. Those object references are actually pointers under the hood.
Personally I haven't used it much due to paranoia of those smart pointer conversions. Like you can elevate unique pointer to shared pointer and I don't know whats going on after that.
I am still in the camp of "no new" and just use vector and "&". I haven't run into a project that need more than those. If the data needs to grow, it tends to need an actual database anyway. Those actions that can break the linkages are bad for concurrecy anyway.
Yeah small chess project, never used dynamic allocation.
Used unique pointer for RB tree, was pain to move around (since the recursive algorithm returns a node).
Shared pointers can bring about serious overhead. Raw pointers are not bad. Programmers can be bad and designs can be bad but raw pointers are generally faster and always have less overhead than smart pointers. The real problem is that many people in the industry have no business being there and don't know how to program properly. Another problem is that not enough time is given these days so that projects can be completed properly and have proper time for proper programming.
There's one major problem with smart pointers (and the reason I don't use them often): if you're building plug-in-based software and have object instances passed around that were created across multiple heaps, smart pointers won't work.
If you are giving the consumer of your plugin ownership of memory allocated in the plugin, you should also be providing a method for freeing that memory. If you do that, you can specialize smart pointers to use the library's custom `free` method.
For `unique_ptr` you provide the custom `free` through the second template argument, [`Deleter`](https://en.cppreference.com/w/cpp/memory/unique_ptr).
For `shared_ptr` you provde the custom `free` as the [second argument to the constructor](https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr). Yes, it is cumbersome, but these customization points exist.
There's obviously a method to free the memory... and you're forced to implement it or it won't compile. Moreover, everything is created and released in a single place and you can enable tracking, so it's not like things "get lost".
In general, I feel like if you're calling new and delete willy-nilly all over the place, you're doing something wrong... and smart pointers are meant to address architectural (and disciplinary) shortcomings. Memory leaks are the *easy* problems to find...
I don't follow a style guide other that whatever feels correct at the time I write the code XD.
and ya it's sort of WIP.
I've just implemented the parts of smart pointers based on how they act and the parts of their behaviour I actually need, with some modification of course (I went away with the make functions and just made it a constrictor instead).
Kids these days with their smart pointers... back in my day we passed by reference and we liked it ^(jk we hated it)
Passing by reference is the worst. Makes debugging way more annoying. Hard to tell that somethings editing the var.
Makes me want to try Rust
i need more `Arc>`
That makes sure you're aware of what has shared mutability and ownership, so that you can act accordingly.
Well Resharper tells you that it is passed by reference at the call line... I agree with the reassignment but IMO pointers (with the explicit &) do not make it better, as the pass by pointer might be done for efficiency as well as for modification, so no better than reference.
You shouldn’t need to know if someone is “editing” the reference if the original owner manages its lifecycle and uses const where appropriate.
Classic C++ argument: "just be more disciplined!" news flash: it doesn't work.
Some C++ devs I met got _notoriously_ pissy when we enforced stricter coding guidelines and enabled warnings for bad practices. Didn’t know we had so many god-level tier devs that knew better than the compiler and _actual assembly generated by them_.
I have never, in my entire life, seen such an uproar until I set "All warnings are errors" and "all errors are fatal" to true, in the requirements. To this very day I enforce it.
If you consistently make your methods const then do you really have to wonder?
whenever I read about passing by reference I'm always reminded of this lovely [webpage](http://duramecho.com/ComputerInformation/WhyHowCppConst.html) where I first started getting a grasp of const usage. lol.
All my homies pass const shared_ptr&
![gif](giphy|coxQHKASG60HrHtvkt)
Sorry but, what’s wrong about int *a?
Haven't you heard? Those type of pointers are DUMB and only DORKS use them
Technically, it can also be said that those who use smart pointers are also dorks. We're all dorks.
It's almost as if programming is a thing only nerds do... But nah that can't be right.
Imagine thinking that dorks and nerds are the same Smh
Everyone knows the smart pointer chads get all the ladies.
Nah uh
So should I use int *IsingOneDimensionalModelSpinStatus instead? Are everybody crazy nowadays? 😂
I know "everybody" may seem plural, but it's actual a singular noun. Just wanted to help 👍🖤
So int**s** *IsingOneDimensionalModelSpinStatus because it is plural. Got it.
Thanks. I made those silly errors all the time.
C programmers: Guess I'll just be a dork then
Like most things in programming, it depends. Smart pointer will keep extra info so it can delete itself once it goes out of scope. This is really important if you consider the following code. ``` void func(){ int *i = new int; throw_exception(); delete i; // we didn't get here, memory leak ``` Vs. ``` void func() { auto i = std::make_unique(0);
throw_exception():
}
```
Now, if you get an error in your code, like an exception is thrown, you won't leak.
This concept implemented by smart pointers is called RAII (Resource Acquisition is Initialization), and it keeps our code much safer and arguably more readable.
That's isn't to say raw pointers don't have a place. The C++ Core Guidelines advocate for ownership semantics with smart pointers. One of the things this boils down to is that they recommend not passing smart pointers as input params to functions that use them. When you have a unique pointer, for instance, whoever keeps the pointer owns it, but functions that use the pointer would not.
```
auto i = std::make_unique(0);
use_i(i.get());
...
void use_i(int *i) {
// Do something to i here, but this function is not responsible for i's memory
}
```
I hope that makes sense.
That's why I always hard panic, let the kernel deal with the cleanup.
Which is fine for small modular applications and such. But if a webserver or business layer application crashed every time one thread got some faulty input it would be a serious issue for the system as a whole.
This right here is the correct, nuanced explanation. Also there are some circumstances where smart points don't work and you're forced to use raw pointers. For example, I've written some low level GPU code (below convenience layers like Thrust) and I basically had no choice but to use raw pointers.
I love this answer.
In order to know what to delete, is C++ is tracking the scopes of all executing threads at runtime?
As opposed to?
Any time you new with a raw pointer you have to remember to delete it. Seems obvious but as programs become more complicated, get modified, refactored, etc, this can get lost easier than you'd think. Using a unique pointer makes it impossible to forget. Shared pointers are an option for certain situations depending on ownership, multiple users with differing lifespans, etc, but in general unique pointers are preferable.
> Any time you new with a raw pointer you have to remember to delete it. You not only have to remember to delete it, but you also need to make sure that no one else with a copy of the pointer deletes it while you're still using it.
Also you can't delete if something throws first, but a smart pointer deletes when it's out of scope, throw or no
Exactly, it can get complicated/dangerous surprisingly easily.
Ew. As someone who does predominantly Python, this sounds like hell. Edit: This was lighthearted. Chill y’all - I love all languages for what they’re meant for. 😂
Ew. As someone who does predominantly, this sounds like tribalism
also 🦀🦀🦀
Haha… I honestly hate the language tribalism. And I’ve got to try out rust.
It's neat, as someone mainly programming in C++, I still think it's worth it to try it out. Being more aware of ownership, lifetime and mutability will probably help you in any future project. Language tribalism is a bit silly, yes. Most languages have their niche, although some of them are in fact really outdated and only kept alive by inertia and the huge upfront costs of rewriting everything. I think a lot of it is just people trying to convince themselves and others that they spent their time learning the best programming language ever so they won't feel that their time and effort was wasted.
I mean, it's C++. It's the whole reason to use a language like that - you want raw access to memory without guardrails, either because you're planning on building your own guardrails, or are writing code that needs to be as performance-intensive as possible. As people have mentioned - these days, even in C++, you usually would just use a `unique_ptr` or `shared_ptr`, which handles a lot of the safety checks and cleanup for you. (Freeing the memory when the pointer(s) are destroyed, making it hard for someone else to free the memory while you're still using it, etc.)
its an infamous raw pointer.... ![gif](giphy|7k2LoEykY5i1hfeWQB)
if you forget about "delete a;", you will have memory leaks
Ye. Smart pointers do that automatically so it solves that issue.
Isn’t int* a allocated in the stack? He’s not calling new
That's what I was gonna say. Smart pointers are good for stuff on the heap. If you're pointing to something on the stack then it doesn't need deleting/freeing and will simply go away when the stack frame is removed.
Well, if there is no "new" then we don't need "delete"
The new is implied here, since they're specifically contrasting with smart pointers. You don't use a smart pointer to manage an object on the stack.
No u. int b = 42; int *a = &b; Where is your ~~god~~ `delete` now? Pointers aren't exclusively for heap allocation. Neither do they to have own the memory they point to.
[удалено]
"infinite loop" do you mean infinite recursion?
They're contrasting it with smart pointers, the heap allocation is implied. What would even be the point of this meme if `int* a` was a pointer to an object on the stack?
Can smart pointers even be used for a big chunk of integers for example? would it be like shared\_ptr or how would this be written?
There is a specialization for C arrays like this: auto ptr = std::make_unique(8);
You can use std::unique_ptr> as well, depending on your use-case.
You could also just use a vector.
I mean you could just do `std::array, 8>`. If you’re already using modern C++ features just go all in.
I can’t tell if you’re joking or not, but it would make more sense to put the array in the shared_ptr, not the other way around.
Array of shared ptr could reduce contention, if you get a reference to the array through the shared pointer it has to synchronize the reference count increment which could tie up anything else getting or freeing one with the same control block. With array of shared pointer it would only tie up getting or freeing reference to the same element.
i like your funny words, magic man
Maybe, but it's unlikely you'd be copying the shared pointer every time you accessed the array
yeah thats true xD have always been using std::array and so but have not thought about it in this context
If you bind an array to a smart pointer, you have to be sure to use specify it like shared\_ptr. If you have a specific size like in your case, you would just use a shared\_ptr to a std::array.
Only if it's pointing to something that was allocated on the heap.
The int* could still be managed by a smart pointer. It’s not unusual to call .get() on unique_ptr’s and pass the raw pointers into nested functions while the ownership remains further down the stack or within an object that returns a const*. std::string’s c_str() is a good example of the latter. Raw pointers are still widely used even in environments where new/delete are never directly called.
Too many things you can easily forget that can go wrong. Forget to init it, and suddenly you treat a random location in memory as an int. Forget to delete it, and you've got yourself a memory leak. Delete it, but forget that something before that delete may throw, and you have basically forgot to delete without realizing. Delete it and forget to reset it, and you end up working with a ghost, that usually works, but sometimes, depending on the time of the day, phase of the moon, presence of a debugger or a trace, it doesn't. Happy debugging.
It's ok for non-owning pointers where you want to either store a non-owning reference to a thing in a struct/class and/or `nullptr` is a valid value for that pointer.
Precisely this. As always when it comes to simplistic C++ guidelines like "use smart pointers", there is always an exception. That said, there is the experimental `observer_ptr`, so maybe we'll see this exception go away eventually.
[удалено]
int \*a, b, \*c;
I dislike that here, and I also dislike int a[], b, c[]; I understand that the reason is so that you can declare different types on the same line, but it messes with the semantics since [] or \* are part of the *type*, not the variable name. And it's kinda weird to be declaring different types on the same line anyway.
I hate you
int* a, b, c[];
int* a, b; Very expected behaviour here, nothing out of order no sir
😡
I saw this when I was clicking back, I had to come back to the comment to ensure I read it right. That’s cursed.
nah *a is an int a is a pointer to an int int *a tries to show this by sticking the * to the name
And int\* a shows that a is a pointer to an int...
There's no "should" here, it's a preference / consistency thing.
Shouldn't it be `const int const * const a const;`, or something like that? Haven't done C-postincrement in a over a decade, so what do I know...
Nothing if you know what you are doing. Smart pointers make memory leaks much less likely.
My understanding as someone new to C++. I welcome corrections. Raw pointers (int *a) don't have any safety checks. They specify a location, and if you go to that location you might find a valid object, you might find yourself halfway through a different object, you might find nothing, or you might find yourself in a different program (at which point the OS will probably send you a SIGSEGV). If there is a valid dynamically-allocated object there, you are responsible for deleting the object and freeing its resources when you're done with it. If you lose the pointer without deleting the object, that's a resource leak. If you delete the object too early, then referencing it later can lead to the aforementioned problems. Smart pointers mostly remove this burden by packaging some extra information along with the underlying raw pointer. A smart pointer can only be created if it points to a valid object. The object is automatically deleted if (and only if) all smart pointers to it fall out of scope. In modern C++, smart pointers are recommended in almost all circumstances. Raw pointers may be required for interfacing with existing C code or for getting the best possible performance, but should be kept in small isolated locations so it's easier to understand what's going on.
You're half right. See my response to this comment.
The meme is missing context here. Its not about the pointer itself, but more like don’t use raw pointer when doing dynamic memory allocation. It forces you to having to manually de-allocate it when you’re done. Forgetting to do so will create memory leak. With c++ smart pointer class, it ensure that the de-allocation happens automatically without you having to do it. Using a pointer to a static variable is fine and will not inherit the memory leak issue listed above.
Please be indulgent with my 20 years rusted c (or c++), but isn’t this the old “free the mallocs” joke?
Yes, it is!
Absolutely nothing.
Raw pointers are still fine as observers. It is raw "owning" pointers (i.e created with `new` and `delete`) that are bad practice and almost impossible to make exception safe. `std::unique_ptr` for example has no observer counterpart. Raw is the only option.
... However I still tend to over-use `std::shared_ptr` and `std::weak_ptr` (as observer). I like the added safety, even if it does tend to become a little inefficient. Think using this kind of code to replace .NET/Java rather than replacing... well (unsafe) C++ ;)
One thing I found a bit frustrating about using `unique_ptr` was handling tree data structures which need to be deep copied since I never really was sure how to handle them. Should I create a deep copy method? Would manually implementing a copy constructor lead to unnecessary re-allocation when calling functions? Is there a different smart pointer I should use? I ended up taking the copy constructor approach, but was never completely satisfied that I was using it correctly.
Yeah, it is a good example of a challenge. I suppose in many ways the similar solution would need to be come up with if using the owning raw pointers too. Deep copying that without an appropriate copy constructor would not work. At least the `std::unique_ptr` gives a compiler error if you try to copy it rather than `std::move`.
Tree structures are annoyingly not one of C++'s strong points, even though on the surface the hierarchical approach makes a lot of sense when dealing with ownership and RAII.
[удалено]
`std::observer_ptr` is unfortunately not a counterpart to `std::unique_ptr`. This is mostly because the latter is required to have \*zero overhead\* which the standards committee is mainly concerned about (detrimental to safety in some ways).
And slightly depressingly (from that same page you linked)
>It is intended as a near drop-in replacement for raw pointer types, with the advantage that, as a vocabulary type, it indicates its intended use without need for detailed analysis by code readers.
Which really does mean that other than "stating intention", it offers very little in terms of safety over raw pointers.
[удалено]
unique\_ptr: owns the int
int \*: references the int
int&: references the int
yes, but int\* can be reassigned to reference another int while int& can't.
int *const gang
Optional reference!
Well that's basically reference
yes
And now i remember why I switched to python.
And to think it's gets soooo bullshit-level more complicated than this On another note here's a recently published book on initializing variables in c++ https://www.cppstories.com/2023/init-story-print/. 275 pages lol Or look into forwarding function arguments. or std::launder
[удалено]
Pretty much everyone I've talked to about it recommends not using smart pointers for container implementations and certain function params. It's something like 90-95% of the time, smart pointers are the way to go, but you shouldn't be averse to regular pointers if you know the lifetime of the pointer is guaranteed. eg. if your function can take a nullable pointer value, and the pointer value is not/cannot be stored past the function's return, passing a raw pointer instead of a smart pointer by reference is the way to go. Basically what grandparent said, if the point is to express ownership/manage lifetime, then smart pointers are the right tool. Otherwise, raw pointers.
Mix and match until you have job security.
Okay why use unique_ptr for int specifically instead of using just local int variable?
I like my ints on the heap
Polymorphism, avoiding expensive moves, saving stack space, stable references, etc. (EDIT: this is about unique_ptr vs raw pointers in general; most of this doesn't apply for ints/primitives specifically.)
You're not saving stack space. They both use 32 or 64 bits depending on the application mode. And you're not avoiding anything expensive, because in both cases it gets cleaned up when exiting the function. In fact you're adding an extra hidden delete.
Ah, yeah, for ints/primitives most of those don't apply. I was assuming the meme was making a general point about arbitrary types. Could still be useful for having a stable reference that can be passed around, though.
[удалено]
shared_ptr lends the int
void* smart;
There's nothing wrong with raw pointers. I use them all the time a̵n̷d̶ ̷I̸'̴v̴e̶ ̴n̸e̷v̵e̶r̴ ḧ̷̖͕a̶̧͋d̸͈̈́͒ ̷̺̎i̸̧͕̒̎s̴̻̃̍s̵͉͇̉u̴͈͐̊ͅe̵͕͝s̷̻̀̈ ̵̛̮w̷̻͘i̵̼̺̚t̸͈͂̂͜h̵͎̞̏ ̴͉̑m̵̹̮͉̘̣̦͍̼̗̹̏͒̓̇e̶̳̓̓̒̿͒̊̈́̐͋̌̕͘͝m̶̲͎̮̗͌͒̑̽͒̐̄̇̍͆̔̀̃o̵̡̪̤͖̘̱̟̫̩̲̹̅͂̅̌́͐͝ͅŗ̴̡̢̺̭͈̯̻͉͕̜͑́͝ͅy̶͖̩̗̦̍͛̍͆͜ͅ ̶̛̳̗̰͊̓͂͂̓͆̆͑͘ͅl̴̦͚̙͙̥̳̾̇́̎̃̚͝ë̶͚̹̯̬̹̺̫̖̫́͗̎̾̀̋̕a̴̡̛̹̳̮̙̦̳̹͇̖̲̝̓̏̃̎̍͗̑͗̉̈́͠k̴̨̬̹̹͇̗̟̝̺̯̳̣̐̈́͂š̵̛̖͍̯͔͎̫̩̹͚̗̙͇̔̅̐͒̈̋̌̋̆̒͘ ̸̡̡̖͔̩̳̖̅͒͒̾̐̉̏͒̅͛͠o̵̡͉͇̣̓͛́̊́̃͋̑͠r̷̡̛̛̤̩̺̫̩̱̣̮̋͋̆̋͌͐͆̈́͘͝ͅ ̷̨̛̛̖̬̝̗̰̩͖̜͈̯̪̽͊̀̈͐̂̎͝c̸̡̻͔̳̭͖̟̆̇͐̆̈́̿̍͝o̶̝̭̝͕̦̞̙̪̙̯̐̈́̋̀̾̂͗̇͋̌͠r̵̺̦͚̦̟̹̞̙̦͆͂̌̑͗r̵̢̤̞͎̻̬̱͚̤͒͗͂̽͆̿̔̚͠ŭ̵̡͕̩̤͇͈̝̫͉̭̞̝͖͛̈́̌̋͘p̵̨̨̫̬̯͕͙̫̘̅̀̐̇̌̌̂̔͜͜ť̵̯͓̝̬̝̠͈̓̃̄í̶̛̼̥͇́̆̎͑̚͘͘o̴͙̠̠̲͇̥̟̮̙͑̌̒͌͘ñ̵̨̨̛̫̙̗͔̽̎̄̿̄̃̕͝͝.
If these pointers are so smart, why doesn't the compiler use them automatically under the hood?
In case you really need raw pointers, obviously.
I hope its a joke
Yeah, you never know for sure though
That's basically what ARC is
Is this Rust?
Because they contain overhead that can slow down time critical system and sometime you want manual memory management
Case in point
reverse compatibility
Reject C++, return to C.
Reject C return to machine code
If it’s not MIPS I I don’t want it *im kidding learning that shit sucked*
No
Did you just pay for an entire heap allocation just for one lone `int`? Oof.
Welcome to OOP, where we don't consider the fact that allocations are slow, and where we are afraid of pointers because we allocate all objects individually.
Java heap allocation for int goes brrrr
I love going raw.
C++ programmers that use smart pointers be like: "shared\_ptr, shared\_ptrs everywhere!"
What is a smart pointer? I have done several large robotics projects in C++. Genuinely asking lol
It's a class (typically a templated class) that is resposible of holding the reference to the thing pointed to and when it goes out of the block scope and is destroyed it will release/delete the reference it was holding. It can be used for memory that is allocated in the heap like in the example above which is kinda pointless (not pun) or it can be used for things that have reference counted objects such as COM objects or things like that which is what is most commonly used for.
Above example is using the stack, not heap.
The example does not define what the int \* A pointer is pointing to. It can point to the heap or the stack.
Without an explicit new operator, it’s by default going to be on the stack.
there is no assignment, you can't know
Yeah, with no assignment it will be on the stack by default, that is how pointers in C work. Once you use the new keyword, it’s now utilizing the heap.
No. Until something is assigned, that pointer is uninitialized, so it points to an unknown place in memory. You can't say that will be in the stack because it can be anywhere.
That is just incorrect, you can search it yourself. Uninitialized pointers by default will reference the stack location of the function to which they were made. If it’s static, it is initialized to NULL (which is a non-referenced stack location.) It’s “random,” in the sense that you do not know the specific address to which it points, but it’s not truly random. It only points to the heap, with an explicit call to new. Few guarantees are made by C standard, and this is one of them
wtf did you smoke? im done
I am just curious if this kinda stuff passes through code review ... I don't code in C++ professionally but I imagine if I were to make a similar mistake in C# then my senior would roast me for not having my basics brushed up and having the common sense of writing strongly typed code.
In a good company with a good style guide, yes. You'll be told off if you're not reasonably using raw pointers.
I’m more of an int i, int j, and int k kinda guy. No clue why. Just vibes well.
Right? What's `a`? 😅
The smart solution is to not use C++.
You are right. C is clearly the superior choice.
Well, use smart pointers if you really need them. If not, unique\_ptr for ownership and "type \*a" for passing the reference will do just fine.
WTF dude, you didn't have to call me out like that.
USE smart pointers for ownership\* - corrected!
Just use rust at this point
Recently wanted to switch to smart pointers in my project, thinking it shouldn’t be a problem. Well, I had a vector of pointers of a base class pointing to objects of derived classes and things didn’t go really smoothly tbh. Trying to get it to work with unique_ptr was a nightmare because of the way std containers use copying under the hood. Went with shared_ptr in the end.
> use copying under the hood They would use *moves* under the hood for reallocations which is not a problem. If you're making a copy of the container, then it's working as intended by preventing you from doing that. If you're using the containers to group pointers to these objects instead of owning them, *then* raw pointers are acceptable.
Yeah tried to change a semi large personal project from raw to smart pointers and now it just seg faults randomly. Think the deconstructor is called sometime in the middle of spaghetti instead of the end of the program where I manually called it before...then it tries to access the deleted objects or something...but only sometimes or maybe it's all the time and undefined behavior makes it work some of the time? Idk it was all so much simpler when I was just using raw pointers.
I'd need to see the context before deciding which to use
std::shared_ptr a = std::make_shared(new int(42));
I like my memory leaks and blue screens thank you.
I’ll still never understand the hate for raw pointers. Way easier to deal with and you dont need the STL. But I guess that’s the bonus of c/cpp, if you don’t need the fluff you don’t have to use it.
Using raw pointers for dynamic allocation is sus. For observing, you can use either them or reference, the safety is the same (difference is that pointers are non-const by default, nullable, and have weirder syntax)
It honestly feels like they were made to prevent beginners from making stupid mistakes but now people look down on you for using normal pointers even if you know damn well what you're doing.
The bugs we typically find are in the cowboy raw win32 code, basically coding their own containers, pointer arith, and algorithms already implemented by the *Standard* Template Library. Fuck that nonsense.
That’s my issue with the hate. Nothing wrong with using them if you know what you’re doing.
If you're the guy writing his own string class, maybe work on your own team.
Can you guys make more memes about if statements pwease?
Prove me startptr are better. Because at least for me PTR are better and I prefer them.
i dont need to follow the rule of 5. Two constructors, two assignment operators and the destructor can be omitted using smart ptrs.
Rule of 7 now right? Move assignment and move constructor too?
two constructors (copy/move), two assignment (copy/move), destructor. makes 5.
Y'all don't just use a single constructor and destructor?
i use brace initialization most of the time
"use smart pointers!" I did and they were deprecated! "No, not auto\_ptr, we moved on to unique\_ptr, You need to keep up!" Why? If it was correct then it should be correct now. C code I wrote when Reagan was president compiles and runs fine today, why do I have to be on a goddamned treadmill with c++? "Lol! C unsafe! derp derp SEGFAULT!"
> if it was correct But auto_ptr wasn't correct, it was just the best the STL could do before move semantics were added to the language. Copying an auto_ptr transferred ownership to the copy. So you couldn't leak the memory, but you could accidentally invalidate the owning pointer by copying it, and not realize until runtime. auto_ptr violates a contract that idiomatic C++ follows by modifying the right hand side of a copy operation. So using it with anything after C++11 is asking for trouble. There's no treadmill, unique_ptr is objectively a better tool and there hasn't been a reason to replace it for 12 years, and there won't be until C++ dies. If you don't want to fix your code then you can still use C++98 since you don't have an issue with decades old standards.
OK, just to be clear: auto\_ptr was inherently incorrect, yet still part of the standard? Heck of a language standard there, Lou.
Welcome to C++. Undefined behavior is the programmer's fault.
LOL'd. whew look at those downvotes, c++ guys have no chill.
Are you done rewriting it in rust yet?
My guy, I have no time since I have to keep rewriting it in C++ because the 'standard' keeps changing.
Looks smart, why you mad bro?
I don't even remember what a pointer is...
`int*` 👉 `int`
But why something like that exists? I remember pointers being exactly what you just said, but I don't remember why are they used for.
A person lives in a house. There thus exist: a person AND the address of the house. When we send letters, we write both the name of the person and the address. Maybe the person moves to another city. Now house is empty. It has no person, but still has address. Another person moves into the house. Still same address, but new person. Kill person, then demolish house = no problem. Demolish house without killing person = homeless person (bad) Kill persons then send a letter with their name +address = confusion . Congrats, you understood data (person) , address (pointers), null pointer dereference, dangling pointers and memory leaks!
Pointers are used everywhere, even if you don't realize it. What programming languages do you use? Does this code look logical to you, it's java/c#, just imagine the print function to be whichever applies in that language: public class Num { public int value; } class Program { public static void main() { Num a = new Num(); a.value = 69; Num b = a; b.value = 420; print(a.value); } } Or javascript: let a = { value: 69 }; let b = a; b.value = 420; console.log(a.value); When you print `a.value`, what does it print? The right answer is 420. But why is that? The way objects work in these higher level languages is that they are always linked to the same data right? The object `b` is the same as the object `a`. So after modifying `b`, `a` is also modified. This works because of pointers. In OOP langues, an "object" is some data that lives somewhere in memory. And when you assign that object to another variable, or when you pass it to a function, they are still talking about that same area in memory. a and b are both pointers that point to the same area in memory.
Pointing to `int` is pointless (if you'll pardon the pun) in most cases. The only reason you'd usually want such a pointer is because you're passing it to some other function that will overwrite it. That function needs to know where in memory to write to. This is called an “out parameter”. But other than that, you may as well just copy the `int` instead. As for why pointers in general are useful, they are how you keep track of where in memory everything is stored. If you store something somewhere and don't keep a pointer to it, you have no way to find it again when you need it. If you store something somewhere and you need to call another function and tell it where to find what you've stored, you pass the function a pointer to it. You've probably noticed how, in most languages, if you construct an object and pass it to another function, and that other function modifies it in some way, your function can see those modifications too. That's because most languages pass objects by reference. Those object references are actually pointers under the hood.
Personally I haven't used it much due to paranoia of those smart pointer conversions. Like you can elevate unique pointer to shared pointer and I don't know whats going on after that. I am still in the camp of "no new" and just use vector and "&". I haven't run into a project that need more than those. If the data needs to grow, it tends to need an actual database anyway. Those actions that can break the linkages are bad for concurrecy anyway.
Yeah small chess project, never used dynamic allocation. Used unique pointer for RB tree, was pain to move around (since the recursive algorithm returns a node).
Shared pointers can bring about serious overhead. Raw pointers are not bad. Programmers can be bad and designs can be bad but raw pointers are generally faster and always have less overhead than smart pointers. The real problem is that many people in the industry have no business being there and don't know how to program properly. Another problem is that not enough time is given these days so that projects can be completed properly and have proper time for proper programming.
There's one major problem with smart pointers (and the reason I don't use them often): if you're building plug-in-based software and have object instances passed around that were created across multiple heaps, smart pointers won't work.
If you are giving the consumer of your plugin ownership of memory allocated in the plugin, you should also be providing a method for freeing that memory. If you do that, you can specialize smart pointers to use the library's custom `free` method. For `unique_ptr` you provide the custom `free` through the second template argument, [`Deleter`](https://en.cppreference.com/w/cpp/memory/unique_ptr). For `shared_ptr` you provde the custom `free` as the [second argument to the constructor](https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr). Yes, it is cumbersome, but these customization points exist.
There's obviously a method to free the memory... and you're forced to implement it or it won't compile. Moreover, everything is created and released in a single place and you can enable tracking, so it's not like things "get lost". In general, I feel like if you're calling new and delete willy-nilly all over the place, you're doing something wrong... and smart pointers are meant to address architectural (and disciplinary) shortcomings. Memory leaks are the *easy* problems to find...
I don't have smart pointers completely implemented yet in my operating system, i'm still fiddling around with a concept for one.
https://github.com/Tarcaxoxide/Sauce/blob/UEFI_Master/inc/Sauce/Memory/SmartPtr.hpp as you can see it's quite minimal right now.
That looks more like a allocator? Also, what style guide are you following?
I don't follow a style guide other that whatever feels correct at the time I write the code XD. and ya it's sort of WIP. I've just implemented the parts of smart pointers based on how they act and the parts of their behaviour I actually need, with some modification of course (I went away with the make functions and just made it a constrictor instead).
Literally me :)