Arrest people for using "new" and "delete"

Pages: 12
There are very few absolutes in the world. It's important to understand why various rules and advice exist. There is always a good reason, but that reason doesn't always apply to the situation at hand.

So when you hear "don't use new and delete" or "globals are evil" or "all data members should be private" or "always use vector<> instead of arrays" etc., you should always ask "why?" Also ask about the costs of following the rule. Armed with this information, you'll know when to follow the rule and when to break it.
Yeah; I had completely misunderstood the actual question. Thanks, Disch.

> Otherwise you will have to write your own wrapper like make_allocated_unique.
> make_unique sees no love from standard comitee, as it deemed trivial to write

To me, it does not look all that trivial; I suppose some library (boost, what else?) could provide a robust and efficient allocate_unique<>() for unique pointers a la std::allocate_shared<>() for shared pointers.

A fair amount of work has to be done before this crude draft outline will reach anywhere near production quality:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template < typename T, typename A > struct deleter_with_allocator
{
    explicit deleter_with_allocator( A& allocator ) : allocator(allocator) {}

    void operator() ( T* ptr ) const
    {
        std::allocator_traits<A> allocator_traits ;
        allocator_traits.destroy( allocator, ptr ) ;
        allocator_traits.deallocate( allocator, ptr, 1 ) ;
    }

    A& allocator ;
};

// TODO: add support for derive class to base class deleter conversions

// TODO: add optimisations for default constructible stateless allocators

template < typename T, typename A, typename... ARGS >
std::unique_ptr< T, deleter_with_allocator<T,A> > allocate_unique( A& allocator, ARGS&&... args )
{
    std::allocator_traits<A> allocator_traits ;
    auto ptr = allocator_traits.allocate( allocator, 1 ) ;

    // TODO: add exception safe RAII wrapper to deallocate the memory and set ptr to nullptr if the constructor throws
    if( ptr ) allocator_traits.construct( allocator, ptr, std::forward<ARGS>(args)... ) ;

    return std::unique_ptr< T, deleter_with_allocator<T,A> >( ptr, deleter_with_allocator<T,A>(allocator) ) ;
}
@dhayden

Your post is a piece of gold well worth remembering. :+)

I guess I should qualify any future general advice with something along similar lines.

Apart from that, I observe that the OP is being introduced to some of the merits of smart pointers.

Any way, I have said before that I value highly any pieces of wisdom that come from professional programmers.

Regards :+)

Disclaimer: I'm writing this post with little time on my phone so don't expect it to be of the highest quality (it's quite half assed if you ask me). If requested I'll rewrite this when I have a bit more time.

As dhayden said, there are very few absolutes in the world, but when respected programmers use words like "always" and "never", beginners follow their word like it's their religion. Instead of teaching to never use something, why not teach when it's acceptable?

There are plenty of times when using new and delete is acceptable... and even malloc and free should be used in plenty of situations, just as there many instances where using a vector over an array is not ideal/recommended. If anyone wants examples I'll be glad to provide some.

The standard library is not a magic bullet and often due to the fact that it's generic, a lot of parts of it are not ideal for a constrained environment. Much of it is not designed with performance in mind, nor with a care for memory allocations, (looking at you, std::string), so often rolling your own specialized implementation of structures is not uncommon and it's something I'd definitely recommend if you find that using the standard library is a bottleneck.

EDIT: Grammar and stuff like that.
Last edited on
@TheIdeasMan, thank you very much for you kind words.

Some day I want to write a book or a blog called Programming Perils (a pun on John Bentley's Programming Perls). The book will concentrate of the trade-offs in programming - the "whys" and "why nots" of different programming ideas. Far too often we teach programmers about a zippy new gizmo without telling them when they should *not* use it. A good example in C++ is exceptions. They are extremely useful, but if misused, they can undo structured programming which was recognized as a good idea in the 1950s.
@dhayden

No worries, credit where credit is due :+)

It seems to me that there is general advice which definitely applies to beginners or intermediate level coders, but the exact opposite of that applies to these groups:

1. Experts who know what they are doing ;
2. Those who have a reason to exploit some behaviour;
3. It is necessary for some library - char * or float for example;
4. An existing code base makes using some feature impossible or uneconomic (exceptions);
5. A constrained environment - memory say (as Avilius mentioned ).

There are probably other examples too.

I have been fooling around with the idea of a singleton with a protected constructor, protected constexpr member variables, which I inherit privately. This is so I use all my constants without qualification, they aren't global, the derived class is not a singleton, and I avoid the overhead of creating these 20 variables 10 million times. The overhead is not so much in that there are 10 million objects, more that the calculation object has 40 odd member variables, so the constants represent an overhead in percentage terms. Maybe there is another way of doing it? I have looked at a few different things.

Any way that is another story, if anyone is interested I can start a new topic. This is the document I am working from - it is chapter's 4 & 5 I have been dabbling with for more than a year due to life's other needs :+)

http://www.icsm.gov.au/gda/gdatm/gdav2.3.pdf


Regards to all :+)
Avilius wrote:
nor with a care for memory allocations, (looking at you, std::string)

std::string doesn't allocate if it's small, at least when it's not defective as in pre-5.0 gcc, and delegates to the user-supplied allocator otherwise. What's careless there?
Last edited on
Topic archived. No new replies allowed.
Pages: 12