Why does make_unique to vector::back() create another copy?

unique_ptr as class member
c unique_ptr example
vector of unique_ptr
initialize unique_ptr
unique_ptr assignment
c++ pass unique_ptr to function
unique_ptr move
unique_ptr implementation

Reproduce a simple example here to demonstrate my question

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>

struct Party {
    Party(std::string value) : value_(value) {};
    std::string value_;
};

int main() {
    std::unordered_map<std::string, std::unique_ptr<Party>> map_;
    std::vector<Party> parties_;

    parties_.emplace_back("AAA");
    parties_.emplace_back("BBB");
    parties_.emplace_back("CCC");

    std::unique_ptr<Party> ptr = std::make_unique<Party>(parties_.back());

    ptr->value_ = "XXX";

    for (auto& p : parties_) {
        std::cout << p.value_ << std::endl; // print: AAA\nBBB\nCCC
    }

}

Essentially, I want to store objects in a vector and have smart pointers pointing to them and to use these pointers to modify the value of the vector's objects.

But it seems like in making a new unique_ptr, parties_.back() actually return a copy of the object instead of the original object.

How do I achieve what I want here? Thank you!

std::make_unique<Party>(something) is essentially equivalent to std::unique_ptr<Party>(new Party(something)), so yes, it is creating new copies of Party objects because you asked for it.

Ultimately here unique_ptr doesn't seem the right choice: if your std::vector is already the sole owner (and manager of lifetime) of the objects, then you don't need to do anything particular, you can just use plain pointers/references. Be advised however that their validity is tied to the references invalidation rules of std::vector - in particular, if it decides to reallocate (which can happen e.g. if you do a push_back) all pointers/references become invalid.

std::unordered_map<std::string, Party*> map_;
std::vector<Party> parties_;

parties_.emplace_back("AAA");
parties_.emplace_back("BBB");
parties_.emplace_back("CCC");

Party *ptr = &parties_.back();

// Notice: if you do parties_.emplace_back("DDD") here
// ptr may become invalid

ptr->value_ = "XXX";

for (auto& p : parties_) {
    std::cout << p.value_ << std::endl; // print: AAA\nBBB\nXXX
}

If you want to be isolated from the effects of reallocation, but are ok with std::vector being the owner, and thus dictating the lifetime, of your objects, you can have an std::vector<std::unique_ptr<Party>> (and, again, keep plain pointers/references to them around)

std::unordered_map<std::string, Party*> map_;
std::vector<std::unique_ptr<Party>> parties_;

parties_.emplace_back(std::make_unique<Party>("AAA"));
parties_.emplace_back(std::make_unique<Party>("BBB"));
parties_.emplace_back(std::make_unique<Party>("CCC"));

Party *ptr = parties_.back().get();

// Notice: if you do parties_.emplace_back(std::make_unique<Party>("DDD"));
// ptr will remain valid

ptr->value_ = "XXX";

for (auto& p : parties_) {
    std::cout << p.value_ << std::endl; // print: AAA\nBBB\nXXX
}

This makes sure that objects are allocated independently from the vector, but if they are removed from the vector they'll be deleted.


OTOH, if you want shared ownership between the vector and the map, you may want std::shared_ptr (which however doesn't come for free, it has to manage reference counting & co.):

std::unordered_map<std::string, std::shared_ptr<Party>> map_;
std::vector<std::shared_ptr<Party>> parties_;

parties_.emplace_back(std::make_shared<Party>("AAA"));
parties_.emplace_back(std::make_shared<Party>("BBB"));
parties_.emplace_back(std::make_shared<Party>("CCC"));

std::shared_ptr<Party> ptr = parties_.back();

// Notice: if you do parties_.emplace_back(std::make_unique<Party>("DDD"));
// ptr will remain valid, but it will still be valid even after
// parties_.pop_back() (ptr will keep the pointed object alive)

ptr->value_ = "XXX";

for (auto& p : parties_) {
    std::cout << p.value_ << std::endl; // print: AAA\nBBB\nXXX
}

This makes sure that the objects' lifetime is not tied to the lifetime of the vector, as any copy of the original std::shared_ptr will (1) point to the same object and (2) keep it alive.

How to: Create and use unique_ptr instances, It cannot be copied to another unique_ptr , passed by value to a function, artist, const std::wstring& title) { // Implicit move operation into the variable that stores the result. return make_unique<Song>(artist, title); } void MakeSongs() shows how to create unique_ptr instances and use them in a vector. C++ We start by seeing what a std::set of std::unique_ptr would represent, and then we see what problem happens when trying to transfer the contents of one set to another. Sets of unique_ptrs: unique and polymorphic. To begin with, you may have wondered why do a unique_ptr on an int as in the above example. Except for showing a simple example, well

std::make_unique<Party>(parties_.back()) creates a new object, always. It's a wrapper for std::unique_ptr<Party>(new Party(parties_.back())). Note that parties_.back() itself is not copying anything, it returns a reference.

In your code ptr does not need to own the Party its points to: parties_ is already the owner. Just use a reference or a raw pointer:

Party &lastParty = parties_.back();
lastParty.value_ = "XXX";

Beware of copies with std::initializer_list!, The calls to std::make_unique() are returning rvalues, so they should simply Surely vector's initializer_list constructor doesn't always copy, does it? We're getting there now, but there's another improvement we can make. Teams. Q&A for Work. Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information.

These two objects

std::unordered_map<std::string, std::unique_ptr<Party>> map_;
std::vector<Party> parties_;

both own the Party instances, as a std::vector always owns its elements, and std::unique_ptr is intended for exclusively owning the pointee. You need to decide which container is supposed to own the parties and manage their lifetimes. Example: std::vector<Party> owns the instances, then you can go with ordinary pointers.

std::unordered_map<std::string, Party*> map_;
std::vector<Party> parties_;

Plain pointers are ok to go with when they don't involve ownership semantics. Once you made this decision, the original question w.r.t. parties_.back() and std::make_unique (which always creates a new instance due to the purpose of std::unique_ptr) is no longer an issue.

unique_ptr, unique_ptr basic 1-1: create unique_ptr from new. make_unique is better than use move to transfer ownership, 2) for new unique_ptr, use make_unique to return unique_ptr<string> temp(new string("yan"); } unique_ptr fun() //support source If your vector should hold std::unique_ptr<Fruit> instead of raw pointers (to  MFC - I have no idea how to combine my C++ code with it, I don't want to create a new MFC project and copy paste my opengl code there. Also, what to do with GLUT managing the window? Please I need to find a portable (simple header, lib, dll cross-platform if possible) that simply works, no bloat, simple buttons and gui elements. Nothing more.

How to Transfer unique_ptrs From a Set to Another Set, Transferring a std::unique_ptr to another std::unique_ptr is an easy std::​unique_ptr<int> p1 = std::make_unique<int>(42); Indeed, the insert methods attemps to make a copy of the unique_ptr Here is how it works with std::vector : When dereferenced, a set's iterator does not return a unique_ptr& , but  My goal is to create approximately 10,000 new dataframes, by unique company_id, with only the relevant rows in that data frame. The first idea I had was to create the collection of data frames shown below, then loop through the original data set and append in new values based on criteria.

15.5, Now that we've covered the fundamentals of move semantics, we can return to the topic of res2 = res1; // Won't compile: copy assignment is disabled Rule: Favor std::array, std::vector, or std::string over a smart pointer managing a fixed use std::make_unique() instead of creating std::unique_ptr and using new yourself. Why is vector push_back throwing a segmentation fault I'm trying to create an n-ary tree by taking user inputs. "t" would be number of test cases, "n" number of nodes in each n-ary trees and "e" number of edges.

Ivor Horton's Beginning Visual C++ 2013, "Person.h" using std::vector; using std::unique_ptr; using std::make_unique; int main() There is an #include directive for the memory header and additional using Within the input loop, each Person object is now created on the heap, and the that will be pointed to by the uniqued_ptr<Person> object it will return. For a gene to give rise to its protein product, an expression vector must be used that contains the appropriate pieces for a host cell to produce the protein. In the case of a mammalian cell, a standard mammalian expression vector will still contain the origin of replication, multiple cloning site, and selectable marker, but it will also need a promoter found in mammalian cells that can drive

Comments
  • The "make" in make_unique means creation ("make me a pizza"), not transformation ("make me a millionaire").
  • Why do you want a pointer, smart or otherwise, to what is already a reference?
  • I think you should just use a reference
  • All answers explain the root cause and provide a fix but I ultimately choose this since if offers multiple alternatives that can be useful for someone else who stumbles upon this and have a slightly different problem.
  • @resnet thank you! Yep, that was exactly the idea when writing this, especially as in the original question it wasn't completely clear what ownership model was called for (and that's fine, it's not always obvious!), I tried to provide the most common alternatives for this kind of problem.