Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If you're using raw pointers in 2021, I think that is a mistake


I'm no C++ expert, but I like mucking about with game projects in C++ every few years, and I'll never not use raw pointers. smart pointers in C++, as well as a lot of these newer language features, really confuse me as to what niche C++ is supposed to fit in. when I use mostly-C-style-C++, I'm using it because I want to drill down into the nitty-gritty, I want to access raw pointers and feel free to do whatever I want with them. I don't want higher-level abstractions over something like pointers, I'm a big boy, I can manage allocating and freeing memory when I need to, I can write my own memory managers and so forth. maybe this is just something domain-specific to game development but I have seen many experienced C/C++ programmers advocate for this as the way to do things in C++, if you're going to use C++, and my (minimal compared to these people) experience (both before and after hearing these perspectives) lines up with what they have to say.

if I was using C++ to write business applications or something, like one would use C# or Java or whatever, then yeah, smart pointers seem like they would be useful in that specific domain... but at that point, why not just use one of those languages, or a language like it?

I'm probably going to try zig for my next endeavor into lower-level game development because that language, while different from the C-style-C++ I'm used to, seems much more in line with the kind of programming I'm looking to do, compared to modern C++. I don't want RAII, smart pointers, and all that conceptual overhead jazz. I want to allocate memory, run operations on said memory, then free said memory. I kinda miss just doing stuff in C89.


You're missing out in a big way.

std::unique_ptr & std::shared_ptr are amazing. If you're still writing new & delete, you're just making things harder on yourself. I'll still use raw pointers in C++, but only the a borrowing context. It massively simplifies ownership. No more reading docs to try and guess if this pointer being passed in or returned needs to be freed or not. If I own it, it's a unique_ptr. If I'm giving it to someone else, it's a unique_ptr&&. If I'm letting something borrow it, it's a raw pointer or reference.

Or I'll make my own smart pointer containers for allocations with special lifecycles, like per-frame allocations from a custom arena allocation that must not be destroyed with delete/free.

Why try to remember all your lifecycle manually, which is incredibly error prone and no you're not immune to mistakes here, when you can compiler-enforce it instead?


In a borrow context, what makes a raw pointer preferable to a weak_ptr or shared_ptr& (or a plain old reference if you don't want it to be optional)?


weak_ptr is a complete different thing, but the meaningful difference between a raw pointer or a shared_ptr& or unique_ptr& is it avoids leaking irrelevant details into the function signature. If the function is only borrowing, it doesn't care about the overall lifetime management (that is, if it's shared, unique, or custom), so that detail shouldn't be part of the function signature.

It also needlessly prevents the function from working in both shared_ptr & unique_ptr contexts.

Same thing for plain old references, although I tend to stick to pointers if the function is mutating as it makes that clearer at the callsite.


That makes sense to me. Why does a pointer imply mutation? I thought that was what const is meant to signal.


It's convention in C++ to pass-by-pointer if the function will mutate the argument. The other way, by (non-const) reference, is discouraged because the function invocation looks the same as the extremely common pass-by-value case.

  void ptr_add(int *f) {
    *f += 5;
  }

  void val_add(int f) {
    f += 5;   // only changes local copy of f
  }

  void ref_add(int &f) {
    f += 5;
  }

  int main() {
    int foo = 42;
    ptr_add(&foo);  // foo is now 47
    val_add(foo);   // foo is still 47
    ref_add(foo);   // foo is now 52
  }


To have either weak_ptr or shared_ptr& you need to have a shared_ptr to begin with. Unless you actively want shared ownership, there's little reason to use shared_ptr.


Well, you "big boys" cause a whole bunch of problems, for limited gain.

There's basically no resource overhead for using the pointer abstractions that C++ offers.

Recall that the original comment was discussing whether to re-write something originally written in Python into C or C++.


true, but I wasn't replying to that, I was replying to your assertion that nobody should use bare pointers in 2021. there is plenty of use for bare pointers in 2021.


> then free said memory

Resource deallocation becomes extremely difficult in the context of (various types of) exception handling. C++ destructors make this a breeze.


absolutely—but I'm also not a fan of exceptions either & don't use them when I write C++. if you write your C++ in a mostly C-style, only taking C++ features here and there as you need them, the complexity of your code is often greatly reduced. again, this may only apply to game development—I haven't used C++ for anything else sizeable, aside from school assignments years ago.


But even in C you have to handle "exceptional situations" somehow... Like, for example, malloc() or fopen() returning NULL (which both could appear in the same block, by the way).


sure, which is why you handle those sort of things in your file-loading and memory-allocating routines accordingly. for high-performance game development you don't malloc() very often, and if you don't have enough memory to run the game, then you handle that by displaying a message or something and then ending the game. you only fopen() in a few specific places when loading resources, and if that fails, then either you made a mistake as a programmer or the user's assets are corrupted. either way, you display a message or something and end the game. in both cases, there's no need to pollute your entire codebase with the headache of exceptions.

like I said, this mindset might be domain-specific, I'm not sure, I haven't used C++ meaningfully for anything else.


> I'm a big boy, I can manage allocating and freeing memory when I need to, I can write my own memory managers and so forth.

Your expertise is laudable and am sure, hard won. The trouble is with expecting a larger team to buy into that philosophy.


my (C/C++) experience is only solo and small team projects, but again, in this specific domain, once you set up a system for memory management, nobody should ever be allocating/freeing anything outside of these systems, so as long as everyone on the team knows how to use the systems, and knows that they shouldn't be mallocing/freeing/newing/deleting things randomly as they see fit, it's not a problem?


There is no problem using raw pointers for non owning pointers. Also a lot of safe abstractions can be built on top of raw pointers (and smart pointers are obviously an example).

Pragmatism beats dogmatism in practice.


> no problem using raw pointers for non owning pointers

No problem, but also little to no benefit. Why get in the habit of using them when you don't have to?


Raw pointers are fine in many contexts, especially when a reference would not do (e.g. when it's optional).


> Raw pointers are fine in many contexts, especially when a reference would not do (e.g. when it's optional).

I didn't say "always use references", I said, never use raw pointers. Since shared_ptrs can be null, I don't see why this is a valid counterargument.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: