-2

I'm learning C++ and I ran into a bit of code that I'm confused on what exactly it does. I'm learning dynamic memory and the place I'm learning it from mentioned that this was good practice.

double * pvalue = NULL;

if(!(pvalue = new double)){
  cout<<"Error: out of memory." << endl;
  exit(1);
}

I understand that you are creating a pointer called pvalue, but I don't understand the if statement. If someone could explain it to me I'd be greatly appreciated.

Sotirios Delimanolis
  • 252,278
  • 54
  • 635
  • 683
  • 1
    Please edit your code! – Héctor C. Mar 09 '18 at 16:04
  • 4
    `new` never returns `nullptr` unless you provide [`std::nothrow`](http://en.cppreference.com/w/cpp/memory/new/nothrow). – François Andrieux Mar 09 '18 at 16:05
  • 2
    And `new` is almost never a 'good practice'. – HolyBlackCat Mar 09 '18 at 16:06
  • 1
    you might find this useful https://stackoverflow.com/questions/26419786/why-doesnt-new-in-c-return-null-on-failure – mathematician1975 Mar 09 '18 at 16:07
  • Thank you very much, if i might ask why is new not a good practice? – Christopher Reif Mar 09 '18 at 16:08
  • Take a look at [this question](https://stackoverflow.com/questions/550451/will-new-return-null-in-any-case) about why some compilers may return null on the new operator instead of throwing exceptions. – Héctor C. Mar 09 '18 at 16:08
  • The only way to win is not to play. If you really need a pointer look at smart pointers. If you need a dynamic array then you have `std::vector`. Let the library work for you is the way to beat the system – NathanOliver Mar 09 '18 at 16:09
  • @ChristopherReif: that's another question, and one that's already been asked and answered: https://stackoverflow.com/q/6500313/10077 – Fred Larson Mar 09 '18 at 16:10
  • Prefer not to use assignments in an `if` statement. Assign as a separate statement, then test. – Thomas Matthews Mar 09 '18 at 16:49
  • 1
    Why not use `new`? Because you the programmer are now responsible for managing the allocated memory and a great many computer programs have died horrible deaths because their programmers wrongly thought they *had* managed their memory. It is astonishing how tricky it can be. The general order of usage preference goes something like: Automatic allocation, [library container](http://en.cppreference.com/w/cpp/container), [smart pointer](http://en.cppreference.com/w/cpp/memory), and `new`. There is stuff below `new`, but it's probably best left alone for now. – user4581301 Mar 09 '18 at 17:15
  • Don't do manual memory management (`new`/`delete`). Use smart pointers and containers. Ohh and don't use `NULL`, use `nullptr`. – Jesper Juhl Mar 09 '18 at 18:20

4 Answers4

3

I'm confused on what exactly it does.

Working with a very outdated notion and limited understanding of C++.

First of all, C++ does not report a failure to allocate memory by returning NULL. It throws an exception, of type std::bad_alloc (which is derived from std::exception).

Second, with the advent of C++11, using "naked" pointers like that is frowned upon, because they all-too-easily result in resource leaks when you forget to delete them, e.g. when an unexpected exception makes your pointer go out of scope.

So you really should use either std::shared_ptr<> or unique_ptr<>.

DevSolar
  • 59,831
  • 18
  • 119
  • 197
  • Arguably worse than a potential leak is the opportunity for dangling pointers when using raw pointers. With smart pointers, you can ensure that visibility and lifetime of the pointee match, so you cannot accidentally dereference a pointer to an object that no longer exists. – IInspectable Mar 10 '18 at 18:07
2
     pvalue = new double   // This allocates a dynamic double as usual
   !(pvalue = new double)  // This takes the value of the resulting pointer
                           // and negates it, checking whether it's null
if(!(pvalue = new double)) // It all becomes the condition for the if.

It's worth noting that:

  • Raw owning pointers must not be used in C++, use smart pointers instead;
  • using namespace std; (which I'm certain this sample has) must not be used;
  • Dynamically allocating a single double is weird;
  • Plain new will never return a null pointer, so the check is meaningless;
  • std::exit will nuke your program mid-flight, leaking all objects with automatic lifetime, return from main instead.

[...] the place I'm learning it from mentioned that this was good practice.

It's time to put on some heavy metal and sunglasses, set fire to "the place" and go find some better learning material.

Quentin
  • 58,778
  • 7
  • 120
  • 175
  • 1
    @ChristopherReif I'm afraid I don't have the best intel, but we have [a curated list of good C++ books](https://stackoverflow.com/q/388242/3233393) that is linked often. I myself found great learning value in just reading Q&A's here on StackOverflow. – Quentin Mar 09 '18 at 16:18
1

This:

if(!(pvalue = new double)){

... is just a (perhaps-too) clever shorthand way of writing this:

pvalue = new double;
if (pvalue == NULL) {...}
Jeremy Friesner
  • 57,675
  • 12
  • 103
  • 196
  • 6
    ...which makes no sense anyway. – HolyBlackCat Mar 09 '18 at 16:06
  • Yes, sure, this does answer the question that was asked. Yet not pointing out, that the check is meaningless in C++ really is grossly negligent. Also, failing to explain, why `if(!some_pointer)` has the same effect (usually) as `if(some_pointer == nullptr)` is also somewhat unsatisfactory. I'm afraid, I need to downvote this submission, because it really is not useful. – IInspectable Mar 10 '18 at 18:19
1

new never returns nullptr unless you provide std::nothrow. Rather, if new fails it will throw std::bad_alloc.

The more appropriate solution would be something like :

#include <iostream>
#include <stdexcept>

double * foo()
{
    double * pvalue = nullptr;

    try {
        pvalue = new double;
    }
    catch(const std::bad_alloc &)   {
        std::cout << "Error: out of memory." << std::endl;
        exit(1);
    }
    return pvalue;
}

However, using raw owning pointers is discouraged in modern code. new is generally avoided in favor of std::make_unique or std::make_shared. For example, an better solution would be something like this :

#include <iostream>
#include <memory>
#include <stdexcept>

std::unique_ptr<double> foo()
{
    try {
        return std::make_unique<double>();
    }
    catch(const std::bad_alloc &)   {
        std::cout << "Error: out of memory." << std::endl;
        exit(1);
    }
}
François Andrieux
  • 24,129
  • 6
  • 46
  • 72