Are there any valid use cases to use new and delete, raw pointers or c-style arrays with modern C++?

前端 未结 19 902
梦谈多话
梦谈多话 2020-11-22 07:20

Here\'s a notable video (Stop teaching C) about that paradigm change to take in teaching the c++ language.

And an also notable blog post

相关标签:
19条回答
  • 2020-11-22 07:40

    There is still a chance to use malloc/free in C++, as you can use new/delete, and anything higher level wrapping the STL memory templates provided.

    I think in order to really learn C++ and especially understand the C++11 memory templates you should create simple structures with new and delete. Just to better understand how they work. All the smart pointer classes rely on those mechanisms. So if you understand what new and delete does, you are going to appreciate the template more and really find smart ways to use them.

    Today I personally try to avoid them as much as possible, but one main reason is the performance, which you should care if it is critical.

    These are my rules of thumb I always have in mind:

    std::shared_ptr: Automatic management of pointers but due to the reference counting it uses for tracing the accessed pointers, you have a worse performance every time you access these objects. Compared simple pointers I would say 6 times slower. Keep in mind, you can use get() and extract the primitive pointer, and continue accessing it. Of you must be careful with that one. I like to as that as a reference with *get(), so the worse performance is not really a deal.

    std::unique_ptr The pointer access may only happen at one point in the code. Because this template forbids copy, thanks to the r-references && feature, it is much faster than an std::shared_ptr. Because there is still some ownership overhead in this class I would say, they are about twice as slow as a primitive pointer. You access the object than the primitive pointer within that template. I also like to use reference trick here, for less required accesses to the object.

    About performance, it might be true, that those templates are slower, but keep in mind that if you want to optimize software, you should profile first and see what really takes many instructions. It is very unlikely that smart-pointers are the problem, but sure it depends on your implementation.

    In C++ no one should care about malloc and free, but they exist for legacy code. They differ basically in the fact, that they know nothing about c++ classes, which with new and delete operator case is different.

    I use std::unique_ptr and std::shared_ptr in my project Commander Genius everywhere and I'm really happy that they exist. I have not to deal with memory leaks and segfaults since then. Before that, we had our own smart-pointer template. So for productive software, I cannot recommend them enough.

    0 讨论(0)
  • 2020-11-22 07:42

    Adding to other answers, there are some cases where new/delete make sense -

    1. Integrating with a 3rd party library which returns the raw pointer and expect you return the pointer to the library once you are done (The library has its own memory management functionality).
    2. Working on resource constrained embedded device where memory (RAM/ROM) is a luxury (even a few kilobytes). Are you sure you want to add more runtime (RAM) and compiled (ROM/Overlay) memory requirement to your application or you want to program carefully with new/delete?
    3. From purist point of view, in some cases smart pointers won't work intuitively (due to their nature). For example, for builder pattern you should to use reinterpret_pointer_cast, if you are using smart pointers. Another case is where you need to cast from a base type to a derived type. You put yourself danger if you get the raw pointer from smart pointer, cast it and put it in another smart pointer and ended up freeing the pointer multiple times.
    0 讨论(0)
  • 2020-11-22 07:43

    When ownership should not be local.

    As an example, a pointer container may not want ownership over the pointers in it to reside in the pointers themselves. If you try to write a linked list with forward unique ptrs, at destruction time you can easily blow the stack.

    A vector-like container of owning pointers may be better suited to storing delete operation at the container or subcontainer level, and not at the element level.

    In those and similar cases, you wrap ownership like a smart pointer does, but you do it at a higher level. Many data structures (graphs, etc) may have similar issues, where ownership properly resides at a higher point than where the pointers are, and they may not map directly to an existing container concept.

    In some cases it may be easy to factor out the container-ownership from the rest of the data structure. In others it may not.

    Sometimes you have insanely complex non-local non-reference counted lifetimes. There is no sane spot to put the ownership pointer in those cases.

    Determining correctness here is hard, but not impossible. Programs that are correct and have such complex ownership semantics exist.


    All of these are corner cases, and few programmers should run into them more than a handful of times in a career.

    0 讨论(0)
  • 2020-11-22 07:43

    For simple use cases, smart pointers, standard containers and references should be enough to use no pointers and raw allocation and de-allocation.

    Now for the cases I can think about:

    • development of containers or other low-level concepts - after all the standard library itself is written in C++ and it does make use of raw pointers, new and delete
    • low level optimization. It should never be a first class concern, because compilers are smart enough to optimize standard code, and maintainability is normally more important than raw performance. But when profiling shows that a block of code represents more than 80% of the execution time, low level optimization makes sense, and thats one of the reasons why the low level C standard library is still a part of C++ standards
    0 讨论(0)
  • 2020-11-22 07:46

    Another use case may be 3rd party library returning raw pointer which is internally covered by own intrusive reference counting (or own memory management - which is not covered by any API/user interface).

    Good example is OpenSceneGraph and their implementation of osg::ref_ptr container and osg::Referenced base class.

    Although it may be possible to use shared_ptr, the intrusive reference counting is way better for scene graph like use cases.

    Personally I do see anything "smart" on the unique_ptr. It is just scope locked new & delete. Although shared_ptr looks way better, it requires overhead which is in many practical cases unacceptable.

    So in general my use case is:

    When dealing with non-STL raw pointer wrappers.

    0 讨论(0)
  • 2020-11-22 07:48

    The OP specificly asks about how/when handrolling will be more efficient in an everyday use case - and I will address that.

    Assuming a modern day compiler/stl/platform, there is not an every day use where handrolled use of new and delete will be more efficient. For the shared_ptr case i believe it will be marginal. In an extremely tight loop(s) there could be something to gain by just using raw new to avoid the ref counting (and find some other method of cleaning up - unless somehow imposed on you, you choose to use shared_ptr for a reason), but that is not an everyday or common example. For the unique_ptr there is not actually any difference, so i think it is safe to say that it is more of rumour and folklore and that performance wise it will not actually matter at all (difference will not be measurable in normal cases).

    There are cases where it is not desirable or possible to use a smart pointer class as already covered by others.

    0 讨论(0)
提交回复
热议问题