Are there any valid use cases to use new and delet

2018-12-31 08:48发布

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

I have a dream ...

I'm dreaming of so called C++ courses/classes/curriculae will stop teaching (requiring) their students to use: ...

Since C++11 as established standard we have the Dynamic memory management facilities aka smart pointers.
Even from earlier standards we have the c++ standard Containers library as a good replacement for raw arrays (allocated with new T[]) (notably usage of std::string instead of c-style NUL terminated character arrays).

Question(s) in bold:

Let aside the placement new override, is there any valid use case that can't be achieved using smart pointers or standard containers but only using new and delete directly (besides implementation of such container/smart pointer classes of course)?

It's sometimes rumored (like here or here) that using new and delete handrolled can be "more efficient" for certain cases. Which are these actually? Don't these edge cases need to keep track of the allocations the same way as standard containers or smart pointers need to do?

Almost the same for raw c-style fixed size arrays: There is std::array nowadays, which allows all kinds of assignment, copying, referencing, etc. easily and syntactically consistent as expected by everyone. Are there any use cases to choose a T myArray[N]; c-style array in preference of std::array<T,N> myArray;?


Regarding interaction with 3rd party libraries:

Assumed a 3rd party library returns raw pointers allocated with new like

MyType* LibApi::CreateNewType() {
    return new MyType(someParams);
}

you can always wrap that to a smart pointer to ensure that delete is called:

std::unique_ptr<MyType> foo = LibApi::CreateNewType();

even if the API requires you to call their legacy function to free the resource like

void LibApi::FreeMyType(MyType* foo);

you still can provide a deleter function:

std::unique_ptr<MyType, LibApi::FreeMyType> foo = LibApi::CreateNewType();

I'm especially interested in valid "every day" use cases in contrast to academic/educational purpose requirements and restrictions, which aren't covered by the mentioned standard facilities.
That new and delete may be used in memory management / garbage collector frameworks or standard container implementation is out of question1.


One major motivation ...

... to ask this question is to give an alternative approach vs any (homework) questions, which are restricted to use any of the constructs mentioned in the title, but serious questions about production ready code.

These are often referred to as the basics of memory management, which is IMO blatantly wrong/misunderstood as suitable for beginners lectures and tasks.


1)Add.: Regarding that paragraph, this should be a clear indicator that new and delete isn't for beginner c++ students, but should be left for the more advanced courses.

标签: c++ c++11
19条回答
弹指情弦暗扣
2楼-- · 2018-12-31 08:57

Another possible valid use case is when you code some garbage collector.

Imagine that you are coding some Scheme interpreter in C++11 (or some Ocaml bytecode interpreter). That language requires you to code a GC (so you need to code one in C++). So ownership is not local, as answered by Yakk. And you want to garbage collect Scheme values, not raw memory!

You probably will end up using explicit new and delete.

In other words, C++11 smart pointers favor some reference counting scheme. But that is a poor GC technique (it is not friendly with circular references, which are common in Scheme).

For example, a naive way of implementing a simple mark-and-sweep GC would be to collect in some global container all the pointers of Scheme values, etc...

Read also the GC handbook.

查看更多
无色无味的生活
3楼-- · 2018-12-31 08:57

When you have to pass something across the DLL boundary. You (almost) can't do that with smart pointers.

查看更多
裙下三千臣
4楼-- · 2018-12-31 08:59

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.

查看更多
春风洒进眼中
5楼-- · 2018-12-31 09:00

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
查看更多
零度萤火
6楼-- · 2018-12-31 09:00

You can still use new and delete if we want to create our own lightweight memory allocation mechanism. For example

1.Using In-Place new : Generally used for allocating from preallocated memory;

char arr[4];

int * intVar = new (&arr) int; // assuming int of size 4 bytes

2.Using Class Specific Allocators : If we want a custom allocator for our own classes.

class AwithCustom {

public:
    void * operator new(size_t size) {
         return malloc(size);
    }

    void operator delete(void * ptr) {
          free(ptr);
    }
};
查看更多
宁负流年不负卿
7楼-- · 2018-12-31 09:02

One valid use case is having to interact with legacy code. Especially if passing raw pointers to functions that take ownership of them.

Not all libraries you use may be using smart pointers and to use them you may need to provide or accept raw pointers and manage their lifetimes manually. This may even be the case within your own codebase if it has a long history.

Another use case is having to interact with C which does not have smart pointers.

查看更多
登录 后发表回答