Thread: Smart Pointers

  1. #1
    Registered User immy's Avatar
    Join Date
    Apr 2014
    Posts
    33

    Smart Pointers

    Hi, I have been reading and watching some tutorials on smart pointers. I understand what they are and why they are used. I don't understand why some people say there are only 2 types of smart pointers....whereas there are several different types of smart pointers: -

    1/unique_ptr
    2/
    shared_ptr
    3/
    weak_ptr
    4/ scoped_ptr

    My question is, which ones are used these days...and which are old fashioned? From some tutorials I have watched, people have said to use shared_ptr everywhere and avoid the rest.

    What is the difference between the four? When do you use each one? Which ones should I avoid?

    I would appreciate if your answers are worded in very simple terms and not tech talk. Thanks
    "Don't quit. Suffer now and live the rest of your life as a champion"
    - Muhammad Ali


  2. #2
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Smart pointers are how C++ exemplifies ownership of data and its lifetime.

    unique_ptrs are sole owners of a piece of data whose lifetime is that of the unique_ptr itself. So if you have a unique_ptr to an allocation, the allocation is deallocated when the unique_ptr dies.

    shared_ptrs represent shared ownership of a piece of data. The data lives as long as the last remaining smart_ptr does. This allows you to manage data across something like threads. By returning shared_ptrs to data, you can safely ensure that it'll eventually be freed even when your code has a large degree of asynchronousness.

    weak_ptrs don't claim ownership of a piece of data until you attempt to access it in which case, it has a method that creates a shared_ptr for you to access the data with. It's a neat little tool. More info here: std::weak_ptr - cppreference.com

    I'm not sure about the last one. But yeah, you can look up things like shared_ptr circular references and the resulting memory leaks and that'll give you an idea of why graph-based structures benefit from a combination of shared and weak pointers.

    This is a good link too: Smart pointer - Wikipedia
    Last edited by MutantJohn; 01-11-2017 at 10:29 PM.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It is true that shared_ptr can subsume all other pointers (except weak_ptr for certain situations). However, shared_ptr has more overhead than unique_ptr and scoped_ptr (which is actually not a smart pointer in the standard library). This is because shared_ptr deals with shared ownership and so has to keep a reference count. unique_ptr does not have to do this as so has less overhead. If that's not enough, unique_ptr has more restrictive semantics (i.e. no copying allowed), which leads to less bugs (you usually should think carefully about copy semantics) and it gives a clear message to someone reading the code--at most one pointer will point to whatever the unique_ptr points to at any time.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    It's also worth noting that if you find yourself move'ing unique_ptr's a lot, there might be something flawed in your design.

    unique_ptrs are nice in the sense that they only support construction and then move semantics while not allowing any form of copying.

    So if you find yourself constantly shifting ownership of the pointed-at data, you might be using the wrong smart pointer or you're not thinking about your lifetimes carefully enough.

    And I think because of RVO, you don't need to
    Code:
    return std::move(my_unique_ptr);
    Instead, you can more often than not just:
    Code:
    return my_unique_ptr;
    if you're writing a function that simply hands off a piece of memory.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's not related to RVO. If you have a local variable that is returned and meets a certain set of requirements, it's implicitly moved when you return it. If RVO kicks in, then the variable won't even be moved. It will be constructed once and moved and copied a total of 0 times.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Oh, that's interesting. I guess I was wrong.

    I assumed it was RVO that was handling that case but is it because function returns are prvalues? I don't mean to get into the language lawyer area, I'm also trying to better understand C++'s expression and value semantics. I know prvalues are like the "pure" rvalues and I think function returns fall into that category so that's why it'd automatically induce move constructors/assignment?

  7. #7
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,609
    Imagine a function with a return type that is an rvalue reference. It is some resource that is near the end of it's lifetime, so it could be moved to preserve it. A value of this description is an xvalue. A prvalue (meaning "pure" rvalue, not like) is an rvalue that is not an xvalue. What I can think of off the top of my head are literals - like numbers or "strings," and so in that case RVO is an option.
    Last edited by whiteflags; 01-13-2017 at 11:03 AM.

  8. #8
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I looked it up and function returns are prvalues. Or at least in this case,
    Code:
    auto my_unique_ptr = get_unique_ptr();
    ,
    get_unique_ptr() is a prvalue. And then this leads to the resolution of:
    Code:
    unique_ptr& operator=( unique_ptr&& r );
    Edit:

    Okay, I tested this in cpp.sh.

    I couldn't not get RVO to work for construction/assignment :P

    But this does show that the function return does indeed invoke move semantics:
    Code:
    // Example program
    #include <iostream>
    
    
    struct moveable
    {
        moveable(void)
        {
            std::cout << "invoking default constructor\n";
        }
            
        moveable(moveable const& rhs) = delete;
        
        moveable(moveable&& rhs)
        {
            std::cout << "invoking move constructor\n";
        }
        
        auto operator=(moveable&& rhs) -> moveable&
        {
            std::cout << "invoking move assignment operator\n";
            return *this;
        }
    };
    
    
    auto get_moveable(void) -> moveable
    {
        moveable m;
        return m;
    }
    
    
    int main(void)
    {
        moveable m;
        m = get_moveable();
        return 0;
    }
    
    /*
    prints:
    invoking default constructor
    invoking default constructor
    invoking move assignment operator
    */
    I'm sure xvalues might do the same? I'm not sure how to manually trigger and create an xvalue.

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >> moveable m;
    >> m = get_moveable();
    Change that to

    auto m = get_moveable();

    and enable optimizations. The former might work if the compiler is smart enough.
    Also, remove "void" from the empty parameter lists.

    EDIT:
    Code:
    struct moveable
    {
    	moveable()
    	{
    		std::cout << "invoking default constructor\n";
    	}
    
    	moveable(moveable const& rhs) = delete;
    
    	moveable(moveable&& rhs)
    	{
    		std::cout << "invoking move constructor\n";
    	}
    
    	auto operator=(moveable&& rhs) -> moveable&
    	{
    		std::cout << "invoking move assignment operator\n";
    		return *this;
    	}
    };
    
    
    auto get_moveable() -> moveable
    {
    	moveable m;
    	return m;
    }
    
    int main()
    {
    	auto m = get_moveable();
    	return 0;
    }
    Output:
    invoking default constructor
    Last edited by Elysia; 01-13-2017 at 01:15 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    I had that too. I assumed that was the RVO kicking in.

    The real goal was to show that the get_moveable() is implicitly convertible to an rvalue reference.

    edit:

    Also, remove "void" from the empty parameter lists.
    Never!!!

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,609
    It isn't that hard to create code that makes xvalues.
    Code:
    int   prvalue();
    int&  lvalue();
    int&& xvalue();
    Xvalues are essentially a middle part of a venn diagram now, they can be lvalue or rvalue in some way, the important thing is that they are eXpiring so you can move them.

    Prvalues are usually literal values like I said, so RVO would be used instead.
    Last edited by whiteflags; 01-13-2017 at 01:32 PM. Reason: how did i get it so wrong

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by MutantJohn View Post
    I had that too. I assumed that was the RVO kicking in.

    The real goal was to show that the get_moveable() is implicitly convertible to an rvalue reference.
    Just disable optimizations:

    invoking default constructor
    invoking move constructor

    edit:
    Never!!!
    Always!!!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,609
    I do like void because it's self-describing, even though I never use it.

  14. #14
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Lol I wonder if this is where the OP thought this thread would go :P

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Smart Pointers
    By cmajor28 in forum C++ Programming
    Replies: 17
    Last Post: 05-10-2015, 12:01 PM
  2. When to use smart pointers?
    By Neo1 in forum C++ Programming
    Replies: 1
    Last Post: 04-15-2012, 10:53 AM
  3. unsure about auto/smart pointers
    By l2u in forum C++ Programming
    Replies: 16
    Last Post: 07-13-2007, 12:55 PM
  4. weak pointers and use_count smart pointers
    By Mario F. in forum C++ Programming
    Replies: 2
    Last Post: 07-29-2006, 07:54 AM
  5. Use Count smart pointers. Need clarification
    By Mario F. in forum C++ Programming
    Replies: 8
    Last Post: 06-26-2006, 03:07 PM

Tags for this Thread