4

I'm new to C++. I've heard that using unique_ptr / shared_ptr is the "way to go" for references to data allocated on the heap. Does it make sense, therefore, to use unique_ptrs instead of std::strings?

einpoklum
  • 86,754
  • 39
  • 223
  • 453
Akira Kido
  • 459
  • 1
  • 5
  • 10

5 Answers5

6

Why would you want to do that?

An std::string object manages the life time of the "contained" string (memory bytes) by itself.

Since you are new to C++. Inside your function / class method, I will advice you create your objects on the stack: Like so:

  std::string s;

as opposed to using the heap:

 std::string* s = new std::string();

Objects created on the stack will be destroyed when your object goes out of scope. So there is no need for smart pointers.

You can following this link to know more: http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

Gamma.X
  • 526
  • 3
  • 9
  • > An std::string object manages the life time of a string by itself. This info was really helpful, plus I though `std::string` was a class. Thanks! – Akira Kido Feb 14 '18 at 03:21
  • The string object doesn't manage life time. It manages resources. The life time of the string object is managed by the language. The C++ Standard also doesn't mention the term *"stack"*, as you are using it. You are confusing an implementation detail with the broader concept: An object with automatic storage duration. @AkiraKido: `std::string` *is* a class (well, an alias for a concrete class template instantiation). I don't know, why that would make a difference, though. – IInspectable Jun 18 '18 at 09:39
  • @IInspectable thanks. I understand your point. However, I didn't confuse anything. I understood the question, and that was the easiest way to explain it. You can see the link: http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/ – Gamma.X Jun 19 '18 at 10:43
  • There are easy ways to lay down concepts, that do not require using wrong or misleading terminology. You *are* using wrong terminology (I pointed out 2 instances previously). You may find that this is nitpicking, but once you've used C++ for a bit, you'll understand the **vital** importance of accuracy. This proposed answer is inaccurate. – IInspectable Jun 19 '18 at 11:55
  • @IInspectable I'm trying to see things from ur point of view. My comment was not misleading in anyway (if you see from mine). The base of the question is about pointers; and pointers points to a memory. I believe using heap and stack memory allocations (in C++) to explain the solution is the simplest way. How easier can you put the solution? You can add a comment to help out; I think that is more needed than insults. – Gamma.X Jun 19 '18 at 12:39
  • Unsure, where you spotted an insult. But anyway, C++ does not describe the concept called stack. You are using an implementation detail to explain (or rather fail to explain) what you meant to explain: Objects with automatic storage duration. There is also no concept called *"heap"* in C++. That's the so-called *"free store"*. Your explanation about who controls lifetime is largely misleading. As I pointed out already, you'll learn to appreciate the vital importance of accuracy. You could have been accurate and just as expressive. – IInspectable Jun 19 '18 at 12:47
2

There's no need to use a std::unique_ptr or std::shared_ptr for a std::string.

You do not have to allocate memory for a simple std::string.

std::string str = "abc";

As simple as that. No need for memory allocation, as the std::string manages the 'real' string by itself.


There are situations which may lead to usage of a pointer, though it is likely a class/struct instance.

For instance consider using

std::unique_ptr<MyClass> p;

instead of

MyClass *p;

if possible.

Blacktempel
  • 3,707
  • 3
  • 24
  • 48
0

You normally don't need pointers to strings, just like you generally don't need pointers to integers. You can just store string values, you can pass string values, etc.

But if you are in the exceptional situation where you'd need a pointer to a string, then yes, std::unique_ptr<std::string> or std::shared_ptr<std::string> are better than std::string*.

MSalters
  • 159,923
  • 8
  • 140
  • 320
  • 3
    Unless the pointer represents a non-owning pointer being passed to a function, and which may be null. – Martin Bonner supports Monica Feb 09 '18 at 11:19
  • @MartinBonner: There's C++17 `std::optional`, see Boost for those who don't have C++17. But I left that out as it's almost certainly not needed. There is hardly any situation in which you need to distinguish between the empty string and no string. – MSalters Feb 09 '18 at 11:24
  • Ah true. In the specific case of `std::string`, needing to distinguish between empty and not present is pretty esoteric. I was thinking in the more general case. – Martin Bonner supports Monica Feb 09 '18 at 11:31
  • 1
    But there is the general principle about *ownership*. Smart pointers are only better at *owning* resources. They are not better at managing resources they don't own. So smart pointers are not interchangeable with raw pointers so that one is *better* than the other. They simply serve a different purpose. – Galik Feb 09 '18 at 11:40
  • @Galik: Actually, for managing resources that someone else owns, `std::weak_ptr` is pretty good. A normal `T*` can go stale. Besides, you also have to consider `T&` for those cases. – MSalters Feb 09 '18 at 13:10
  • `std::weak_ptr` also has a completely different purpose to raw pointers. They are not interchangeable. `std::weak_ptr` is very inefficient but very useful in niche situations where it is required that the resource can disappear. Yes `T&` should be preferred but not always applicable. – Galik Feb 09 '18 at 13:42
  • @Galik: So you get into the niche case of "no ownership, but also no managed ownership elsewhere so `weak_ptr` is inappropriate, and a normal reference is also inapplicable for unspecified reasons". – MSalters Feb 09 '18 at 13:46
  • 1
    @MSalters My main point is that it is not an "either/or" between smart pointers and raw pointers. Each is best in certain situations. If you tell people to always use smart pointers, they try to use `unique_ptr` and where that doesn't work they use `shared_ptr` for everything else. That's not good practice. – Galik Feb 09 '18 at 13:52
0

An std::unique_ptr ensures that the object pointed is not accidentally copied and properly deleted. As you should avoid dynamic allocation as much as you can, you can simply keep the std::string as a member of your class. If it is a returned value, as already pointed out, the string class is smart enough to properly move resources in a safe way. You don't need to guarantee that a string is unique, I mean, no copies exist, so the unique ptr is just a too strong constraint. KIS rule: Keep it simple.

Stefano Buora
  • 1,012
  • 6
  • 11
0

Usually, and by default the answer is no, as others have suggested. However - sometimes, the answer may paradoxically be "Possibly Yes"! How come?

  • With std::string, you don't control how, when and by whom your buffer is allocated. While this is somewhat mitigated if you use a different allocator (std::basic_string<char, MyAllocatorType>) - the resulting class is not std::string; and will generally not be accepted by functions which taken std::string's. And it may not make sense to get into allocators just for this purpose.
  • More specifically, you can allow your unique-pointer-based string class to be created as an owning wrapper for an existing buffer.
  • Now that we can use string_view's - and they are even in the standard in C++20 (std::string_view) - you don't have to rewrite the whole string class for unique-pointer-based strings; all you need is to create a string view over it, using the raw pointer and the size in bytes (or size - 1 if you want better null-termination safety.) And if you do want the std::string methods still, they'll be one-liners, e.g.
    std::string_view view() const { 
         return std::string_view{uptr_.get(), size_}; 
    }
    substr(size_type pos = 0, size_type count = npos) const { 
         return view().substr(pos, count); 
    }
    
  • If you want to update a string in-place, while maintaining its size - an std::string won't work for you: Either its completely constant, or mutable both in size and in contents.
einpoklum
  • 86,754
  • 39
  • 223
  • 453