代码之家  ›  专栏  ›  技术社区  ›  lo tolmencre

为什么从引用生成共享指针会复制对象?

  •  2
  • lo tolmencre  · 技术社区  · 8 年前

    我打算让构造函数接受引用,然后创建指向作为引用传递的对象的指针,并将这些指针存储在字段中。然而,由于某种原因,我这样做的方式正在创建副本,我不明白为什么:

    #include <iostream>
    #include <vector>
    #include <memory>
    
    // the class with the field of pointers
    template<class T, class... Types>
    class C
    {
    
    private:
        std::vector<std::shared_ptr<T>> mem; // the field of pointers
    
    public:
        C(T& t, Types&... args)
          // make pointers to the objects passed by reference and store them in mem
          : mem{ std::make_shared<T>(t), std::make_shared<T>(args)... }
        {
    
            // to demonstrate that the pointers point to copies, alter one of the objects (subscript operator expected)
            (*mem[0])[0] = 10;
    
    
            // demonstrate the effect on the local copies
            std::cout << "vectors in mem:" << "\n";
            for (const auto& x : mem) {
                for (const auto& y : *x) {
                    std::cout << y << ' ';
                }
                std::cout << "\n";
            }
        }
    };
    
    int main()
    {
        std::vector<int> v1{ 1, 2, 3 };
        std::vector<int> v2{ 1, 2, 3 };
        std::vector<int> v3{ 1, 2, 3 };
    
        // make an object of type C with some vectors to store pointers to in field mem
        C<std::vector<int>, std::vector<int>, std::vector<int>> c(v1, v2, v3);
    
        // demonstrate that original vectors are unaltered
        std::cout << "original vectors:"<< "\n";
    
        for (const auto& y : v1) {
            std::cout << y << ' ';
        }
        std::cout << "\n";
    
        for (const auto& y : v2) {
            std::cout << y << ' ';
        }
        std::cout << "\n";
    
        for (const auto& y : v3) {
            std::cout << y << ' ';
        }
        std::cout << "\n";
    }
    

    我错过了什么?复制发生在哪里?为什么?

    3 回复  |  直到 8 年前
        1
  •  2
  •   StoryTeller - Unslander Monica    8 年前

    std::make_shared<T>(t) . make_shared 将调用的构造函数 T T 参照左值。

    到你被传递的对象

    我建议您改为通过智能指针接受参数。它使您的类的用户能够从API本身清楚地了解所有权语义。

        2
  •  2
  •   YSC    8 年前

    我错过了什么?复制发生在哪里?为什么?

    从字面上回答问题 cppreference.com :

    template< class T, class... Args > shared_ptr<T> make_shared( Args&&... args ); 构造类型的对象 T std::shared_ptr 使用 args 作为构造函数的参数列表 .

    std::make_shared<T>(t) ( t T& )调用 T::T(T const&) 并建立一个 属于 。错误的解决方案是创建 std::shared\u ptr std::make_shared …但在这种情况下,您将创建指向潜在静态分配对象的智能指针。这是 令人不快的 未定义的行为

    C(std::shared_ptr<T> t, std::shared_ptr<Types> ...args) { /* ... */ }
    
        3
  •  2
  •   Mr.C64    8 年前

    std::make_shared<T> 分配一块足够大的内存来存储T类型的对象(使用传递的参数初始化它,如果有的话),并在其上附加一个控制块来管理共享所有权(如保持对象引用计数等)。

    +---------------+
    | Control block |
    |               |
    + ............. +
    |  Object (T)   |
    |               |
    +---------------+
    

    所以,即使你通过了 对于一个对象, make_shared 将创造自己的“深度”

    推荐文章