Main Content

AUTOSAR C++14 Rule A20-8-5

std::make_unique shall be used to construct objects owned by std::unique_ptr

Since R2020b

Description

Rule Definition

std::make_unique shall be used to construct objects owned by std::unique_ptr.

Rationale

Instead of allocating memory by using the new operator and converting the resulting raw pointer to an std::unique_ptr object, for instance:

class numberClass {
   public:
     numberClass(int n): number(n){}
   private: 
     int number;
}
int aNumber=1; 
std::unique_ptr<numberClass> numberPtr (new numberClass(aNumber)); 
Create a std::unique_ptr object directly using the std::make_unique function. For instance:
auto numberPtr = std::make_unique<numberClass>(aNumber);

Using std::make_unique is preferred because:

  • The creation of the std::unique_ptr object using std::make_unique is exception-safe. Otherwise, an exception can occur between the dynamic memory allocation with the new operator and the subsequent conversion, leading to a memory leak. An exception causes a memory leak only in certain contexts, for instance, when the std::unique_ptr object is created in an argument of a multi-parameter function and another function argument evaluation throws an exception.

  • You can use a more concise syntax. You do not have to repeat the data type of the object that is dynamically allocated.

Polyspace Implementation

The checker flags the creation of an std::unique_ptr object (or boost::unique_ptr object) from the raw pointer returned by the new operator.

Troubleshooting

If you expect a rule violation but Polyspace® does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <cstdint>
#include <string>

class Record {
    public:
       Record(std::string aName, std::string someInfo): name(aName), info(someInfo){       
       }
    private:
       std::string name;
       std::string info;
};

void addRecordToDataBase(std::unique_ptr<Record> aRecord, bool dataBaseIsFull);
bool checkDataBase(void); //Checks if database can accept more entries

void createRecord() {
    std::unique_ptr<Record> recordPtr1 (new Record("John", "Mechanic, New York")); //Noncompliant
    auto recordPtr2 = std::make_unique<Record>("Tom", "Plumber, Boston"); //Compliant
    
    addRecordToDataBase(std::unique_ptr<Record>(new Record("John", "Mechanic, New York")), checkDataBase()); //Noncompliant
    addRecordToDataBase(std::make_unique<Record>("Tom", "Plumber, Boston"), checkDataBase()); //Compliant
}

In this example, the rule is violated whenever the new operator returns a raw pointer and a subsequent conversion creates an std::unique_ptr object from the raw pointer.

In the first call to addRecordToDatabase, the following sequence of events can occur (prior to C++17):

  • First argument evaluation. The new operator dynamically allocates memory for a Record object.

  • Second argument evaluation. The function checkDataBase is called.

  • Continuation of first argument evaluation. The raw pointer obtained from the new operator is converted to an std::unique_ptr object.

If the second step throws an exception, the raw pointer is not assigned to the resource management object and results in a memory leak.

Check Information

Group: General utilities library
Category: Required, Automated

Version History

Introduced in R2020b

expand all