没有对 'push_back' 的匹配成员函数调用,共享指针向量

No matching member function call to 'push_back', vector of shared pointers

我有一个 Container class 用于存储共享指针的向量。每当一个项目附加到 Container,我希望它承担该项目的所有权。换句话说,当Container被解构时,它里面的所有元素也应该被解构。

template <typename T>
class Container
{
private:
    const std::vector<std::shared_ptr<T>> vec_;


public:
    void append(std::shared_ptr<T> item)
    {
        vec_.push_back(std::move(item));
    }

    void printElements()
    {
        for (int i = 0; i < vec_.size(); i++) { std::cout << vec_[i] << std::endl; }
    }
};

int main(int argc, char** argv) {

    std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();
    c->append(std::make_shared<std::string>("hello"));

    return 0;
}

问题是,我在 vec_.push_back(std::move(item)) 上收到以下错误。

No matching member function for call to 'push_back'

我不确定为什么会出现此错误。

原回答:

你的 std::vectorvec_const。在我看来,这会强制删除或禁用任何方法,例如 push_back(),它试图修改 const 向量。


2020 年 5 月 10 日添加的内容:

我认为@Carpetfizz 在他的问题下的评论中的评论也值得阐述:

@GabrielStaples thanks, removing const did the trick. I thought const only protected against reassignment of vector_ but allowed for it to be mutated?

我的回复:

No, const here applies to the contents of the vector. The vector isn't a pointer, but what you're talking about could be done with pointers, by making the pointer itself const instead of the contents of what it points to const. Also, const and mutable are opposites. One undoes the other. You cannot have both in effect at the same time. By definition, something constant is immutable (unchangeable), and something mutable is non-constant.

如何使指针成为 const 而不是它指向的内容?

首先,考虑原始代码(我做了一些小的 modifications/fixes):

运行 自己上网:https://onlinegdb.com/SyMqoeU9L

1) cpp_template_const_vector_of_smart_ptrs_test_BEFORE.cpp:

#include <iostream>
#include <memory>
#include <vector>

template <typename T>
class Container
{
private:
    // const std::vector<std::shared_ptr<T>> vec_; // does NOT work 
    std::vector<std::shared_ptr<T>> vec_;          // works!


public:
    void append(std::shared_ptr<T> item)
    {
        vec_.push_back(std::move(item));
    }

    void printElements()
    {
        for (int i = 0; i < vec_.size(); i++) 
        { 
            // Don't forget to dereference the pointer with `*` in order to 
            // obtain the _contens of the pointer_ (ie: what it points to),
            // rather than the pointer (address) itself
            std::cout << *vec_[i] << std::endl; 
        }
    }
};

int main(int argc, char** argv) 
{
    std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();

    c->append(std::make_shared<std::string>("hello"));
    c->append(std::make_shared<std::string>("world"));

    c->printElements();

    return 0;
}

输出:

hello
world

下面是演示如何创建指向非常量向量的常量指针的新代码。在这里查看我的评论,并研究更改:

运行 自己上网:https://onlinegdb.com/HyjNx-L5U

2) cpp_template_const_vector_of_smart_ptrs_test_AFTER.cpp

#include <iostream>
#include <memory>
#include <vector>

template <typename T>
class Container
{
private:
    // const std::vector<std::shared_ptr<T>> vec_; // does NOT work 

    // Create an alias to this type just to make the creation below less 
    // redundant in typing out the long type 
    using vec_type = std::vector<std::shared_ptr<T>>;

    // NON-const object (vector)--so it can be changed 
    vec_type vec_;
    // const pointer to NON-const object--so, vec_p_ can NOT be re-assigned to
    // point to a new vector, because it is `const`! But, **what it points to**
    // CAN be changed because it is NOT const!
    vec_type * const vec_p_ = &vec_;

    // This also does NOT work (in place of the line above) because it makes 
    // the **contents of what you're pointing to const**, which means again 
    // that the contents of the vector can NOT be modified. 
    // const vec_type * const vec_p_ = &vec_; // does NOT work 
    // Here's the compile-time error in gcc when compiling for C++17:
    //      main.cpp: In instantiation of ‘void Container<T>::append(std::shared_ptr<_Tp>) [with T = std::basic_string<char>]’:
    //      <span class="error_line" onclick="ide.gotoLine('main.cpp',78)">main.cpp:78:53</span>:   required from here
    //      main.cpp:61:9: error: passing ‘const vec_type {aka const std::vector >, std::allocator > > >}’ as ‘this’ argument discards qualifiers [-fpermissive]
    //               vec_p_->push_back(std::move(item));
    //               ^~~~~~
    //      In file included from /usr/include/c++/7/vector:64:0,
    //                       from main.cpp:22:
    //      /usr/include/c++/7/bits/stl_vector.h:953:7: note:   in call to ‘void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::shared_ptr >; _Alloc = std::allocator > >; std::vector<_Tp, _Alloc>::value_type = std::shared_ptr >]’
    //             push_back(value_type&& __x)
    //             ^~~~~~~~~


    // To prove that vec_p_ can NOT be re-assigned to point to a new vector, 
    // watch this:
    vec_type vec2_;
    // vec_p_ = &vec2_; // COMPILE-TIME ERROR! Here is the error:
    //      main.cpp:44:5: error: ‘vec_p_’ does not name a type; did you mean ‘vec_type’?
    //           vec_p_ = &vec2_; // COMPILE-TIME ERROR!
    //           ^~~~~~
    //           vec_type

    // BUT, this works just fine:
    vec_type * vec_p2_ = &vec2_; // non-const pointer to non-const data 

public:
    void append(std::shared_ptr<T> item)
    {
        vec_p_->push_back(std::move(item));
    }

    void printElements()
    {
        for (int i = 0; i < vec_p_->size(); i++) 
        { 
            // Notice we have to use a double de-reference here now!
            std::cout << *(*vec_p_)[i] << std::endl; 
        }
    }
};

int main(int argc, char** argv) 
{
    std::unique_ptr<Container<std::string>> c = std::make_unique<Container<std::string>>();

    c->append(std::make_shared<std::string>("hello"));
    c->append(std::make_shared<std::string>("world"));

    c->printElements();

    return 0;
}

输出:

hello
world