c++shared

How do I understand how std::make_shared works?


I came across an elegant line of reading a binary file into a vector like this (that works):

std::ifstream ifs("myfile.bin", std::ios::binary);
std::vector<char> buffer(std::istreambuf_iterator<char>(ifs), {});

Instead since I want my vector to be a shared pointer I write:

std::ifstream ifs("myfile.bin", std::ios::binary);
auto sp = std::make_shared<std::vector<char>>(std::istreambuf_iterator<char>(ifs), {});

I.e just pass the vector constructor arguments to make_shared (as I usually do to create any shared pointer of any objects). But I get: error: no matching function for call to 'make_shared'?

Detailed output:

/usr/include/c++/11.1.0/bits/shared_ptr.h|873 col 5| note: candidate template ignored: substitution failure [with _Tp = std::vector<char, std::allocator>]: deduced incomplete pack <std::istreambuf_iterator<char, std::char_traits >, (no value)> for template parameter '_Args' || make_shared(_Args&&... __args)


Solution

  • This will work:

    std::ifstream ifs("myfile.bin", std::ios::binary);
    auto sp = std::make_shared<std::vector<char>>(std::istreambuf_iterator<char>(ifs),
        std::istreambuf_iterator<char>{});
    

    This is because you are using this variadic template:

    template<class T, class... Args>
    shared_ptr<T> make_shared( Args&&... args );
    

    where every single argument type must be deducable, if not manually instantited. '{}' doesn't allow for argument deduction, hence the compiler error. That being sad, you can also explicitly instantiate the template:

    auto sp = std::make_shared<std::vector<char>, std::istreambuf_iterator<char>,
        std::istreambuf_iterator<char>>({ifs}, {});
    

    In both cases, a type alias for the iterator might improve readability (using InputIt = std::istreambuf_iterator<char>; or something along those lines).