0

I want to create a wchar_t* which length is dynamic. So I decided to write the following function:

std::unique_ptr<wchar_t> mem::TO_WCHAR_T_PTR(char* str)
{
    size_t len = strlen(str) + 1; // Size of my wchar_t string
    std::unique_ptr<wchar_t> wStr_ptr(new wchar_t[len]); // Compiler supports C++17

    size_t convertedChars = 0;

    mbstowcs_s(&convertedChars, wStr_ptr.get(), len, str, _TRUNCATE);

    return wStr_ptr; // Is this save to use?
}

int main(int argc, char** argv)
{
    char str[] = "Hello world";
    auto ptr1 = TO_WCHAR_T_PTR(str);

     // Do some stuff ...

    return 0;
} // ptr1 out of scope so it gets deleted or was it already deleted(?)

My question: Is it ok to use smart-pointert by value or do I need to pass them by reference? I know about move when using unique_ptr I just want to make sure I can use the smart_ptr like this. The next question: Does it work with shared_ptr as well?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
AidenDean
  • 318
  • 2
  • 14
  • 2
    Returning a reference to a local variable is UB, so the only way to return it is by value. – tkausl Sep 18 '21 at 20:49
  • 1
    "_I want to create a `wchar_t*` which length is dynamic_" - there is already a solution for that and it's a `std::wstring` – Ted Lyngmo Sep 18 '21 at 20:51
  • I'd expect `unique_ptr` to use `delete`, while it should use `delete[]`. Why aren't you using one of the standard containers instead of trying to encapsulate a raw array? That as introduction, make sure you submit your code for review on codereview.stackexchange.com! – Ulrich Eckhardt Sep 18 '21 at 20:51
  • From [cppreference](https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr) about the move constructor for `std::unique_ptr` (the copy c'tor is deleted, so your function can't use that for the return value): *Constructs a unique_ptr by transferring ownership from u to *this and stores the null pointer in u.* – Adrian Mole Sep 18 '21 at 20:57
  • 1
    `std::unique_ptr wStr_ptr(new wchar_t[len])` should be `std::unique_ptr wStr_ptr(new wchar_t[len])` – Ted Lyngmo Sep 18 '21 at 20:57
  • One more thing: It's completely irrelevant that the returned object is a smart pointer. The rules don't change depending on the type of object. – Ulrich Eckhardt Sep 18 '21 at 20:57
  • "I want to create a wchar_t* which length is dynamic". That is an unnecessarily low level requirement. Use a `std::wstring` or a `std::vector` - both provide a means to access a pointer to the data they manage. The fact they manage their data (e.g. when resizing or cleaning up when required) is an advantage since, if you work with a raw pointer, YOU will have to manage the data - and that is error-prone, often difficult to get right, and a good way to introduce unnecessary bugs that are hard to find into your program. – Peter Sep 18 '21 at 21:18

2 Answers2

3

Your way of returning std::unique_ptr is correct. It'll either be placed in ptr1 directly via NRVO (Named Return Value Optimization) or moved into it. You should NOT return std::move(wStr_ptr), however, since that will prevent (N)RVO. And it works the same way for std::shared_ptr.

Matthias Grün
  • 1,466
  • 1
  • 7
  • 12
1

I want to create a wchar_t* which length is dynamic.

So use an std::wstring. Or if it's not an actual string, perhaps an std::vector<wchar_t>.

A unique_ptr doesn't help you here in any way. And why forego the information you have about the allocated size?


Also, @tkausl is correct in that you can't return a reference to a local variable, it's undefined behavior; and @TedLyngmo correctly points out that you're using the wrong type of unique_ptr, since you're allocating a sequence of elements, not just one.

einpoklum
  • 118,144
  • 57
  • 340
  • 684