1

Here is my code that I'm getting (Warning C26409 Avoid calling new and delete explicitly, use std::make_unique instead (r.11).) after doing a Visual Studio 2019 Code Analysis:

#include <windows.h>
#include <strsafe.h>
int main()
{
    auto *sResult = new WCHAR[256];
    StringCchPrintfW(sResult, 256, L"this is a %s", L"test");
    delete[] sResult;
}

I was under the assumption to use new/delete instead of calloc/free, but now the compiler is telling me to use std::make_unique. I can't find any examples on how I can change my code to be compliant.

So my questions are:

  1. how do I change my code so it doens't use new/delete

  2. why should I not use new/delte vs std::make_unique?

JeffR
  • 765
  • 2
  • 8
  • 23
  • When asking about build errors or warnings, please always include a full and complete copy-paste (as text) of the build output. Not everyone knows by heart what `C26409` might be. – Some programmer dude Mar 20 '22 at 11:42
  • 1
    Btw. `(r.11)` references the item in the C++ core guidelines that is violated. [Here](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-newdelete) is the item with explanation. And [here](https://learn.microsoft.com/en-us/cpp/code-quality/c26409?view=msvc-160) is Microsoft's detailed explanation of the warning. – user17732522 Mar 20 '22 at 11:47
  • 2
    In terms of "why should I not use new/delete", this is explained in numerous "introduction to smart pointers" guides on the web, such as this one: https://www.codeproject.com/Articles/541067/Cplusplus-Smart-Pointers – Den-Jason Mar 20 '22 at 11:59

2 Answers2

10

The warning is somewhat confusing, because it assumes that you need some direct memory allocation. If fact, you don't:

#include <windows.h>
#include <strsafe.h>
#include <vector>
int main()
{
    std::vector<WCHAR> sResult(256);
    StringCchPrintfW(sResult.data(), sResult.size(), L"this is a %s", L"test");
}

or

int main()
{
    WCHAR sResult[256];
    StringCchPrintfW(sResult, 256, L"this is a %s", L"test");
}

The idea is to use static storage when you can (small data) to be more efficient (no OS memory call), and use std::vector when you must allocate because the size is either unknown at compile time or too big for the stack and let STL do the work for you. The usage of std::make_unique is when you indeed need to call new directly or indirectly and have it auto-destruct later.

TL;DR: Read about modern C++ memory management.

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
2

Here's how you could rewrite this using std::unique_ptr. Note that the use of std::vector<WCHAR>, std::wstring or an array allocated on the stack would be preferable:

#include <memory>

...

{
    auto sResult = std::make_unique<WCHAR[]>(256);
    StringCchPrintfW(sResult.get(), 256, L"this is a %s", L"test");
} // exiting the scope frees the memory

Why should you do this (or use std::vector or similar?

It simplifies the code, since you don't need to think about how the function is exited; the compiler ensures the resources are freed. Otherwise you need to make sure for every execution path including ones that throw an exception or return early free all resources. The programming technique is called RAII (Resource Allocation Is Initialization) in C++.


Note: Given the small amount of memory you allocate, you may want to create the memory on the stack though. This should also get rid of the error by removing any dynamic memory allocations:

WCHAR sResult[256];
StringCchPrintfW(sResult, 256, L"this is a %s", L"test");
fabian
  • 80,457
  • 12
  • 86
  • 114
  • 1
    @JeffR it's part of the `memory` standard library header: https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique – fabian Mar 20 '22 at 12:11
  • so a `.get()` is used to store the value into the variable (seems opposite), so what is the operator to "read" the value stored in sResult? – JeffR Mar 20 '22 at 12:12
  • 1
    @Jeff `std::unique_ptr::get` gives access to the raw pointer. This is reading the value, but for array parameters `std::unique_ptr` implements the `[]` operator in addition to that. To replace the array, you'd use the move assignment operator or `reset()`. There's a good documentation of unique_ptr here: https://en.cppreference.com/w/cpp/memory/unique_ptr Doesn't teach you necessarily about how to use it though ;) – fabian Mar 20 '22 at 12:16