如何索引到C ++ shared_ptr / unique_ptr数组?

时间:2015-05-17 02:50:01

标签: c++ arrays c++11 shared-ptr unique-ptr

受到Demo of shared ptr array

的启发

我得到了前两行:

std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
*sp = "john";
auto p = &(* sp);
++p = new string("Paul");
++p = new string("Mary");
for(auto q = &(*sp); q <= p; q++) cout << *q << endl;

(1)有人可以告诉我如何访问我的数组的后续元素并使用for循环打印出来吗?

我的for循环不打印任何MSVC V19和g ++ v4.9打印“john”但不打印“Paul”和“Mary”然后给我一个分段错误。

现在经过一些谷歌/ bing搜索后,我发现一些讨论建议如果我不分享它,我应该使用unique_ptr

所以我需要进行更多实验,这有效:

  const int len=3;
  std::unique_ptr<string[]> up( new string[len] ); // this will correctly call delete[]
  up[0] = "john";
  up[1] = "paul";
  up[2] = "mary";
  for(int ii = 0; ii < len; ++ii) cout << up[ii] << endl;

(2)有没有办法打印数组而不用硬编码长度?我希望有一种方法可以使新的C ++ for循环语法工作,但它似乎只适用于std::arraystd::vector

(3)有没有更简单的方法来初始化这个数组?也许有一个初始化列表?

3 个答案:

答案 0 :(得分:2)

要访问后续元素,请使用shared_ptr::get成员函数

std::shared_ptr<string> sp( new string[3], std::default_delete<string[]>() );
sp.get()[0] = "John";
sp.get()[1] = "Paul";
sp.get()[2] = "Mary";
for(auto q = sp.get(); q < sp.get() + 3; q++) cout << *q << endl;

解除引用shared_ptr的问题在于它会返回string&,但您希望能够访问基础指针,以便能够索引到下一个元素。 / p>

您还可以在构建时使用列表初始化

初始化shared_ptr数组
std::shared_ptr<string> sp( new string[3]{"John", "Paul", "Mary"}, 
                            std::default_delete<string[]>() );

对于unique_ptr,正如您所指出的那样,存在一种部分特化,可以正确删除数组类型。但是,它不存储数组的长度,您需要单独存储它并将其与unique_ptr一起传递。对于单行初始化,您可以使用与上面相同的语法。

std::unique_ptr<string[]> up( new string[len]{"John", "Paul", "Mary"} );

但是,shared_ptrunique_ptr都不能与基于范围的for循环一起使用。范围的specification要求操作数要么是数组,要么必须具有begin()end()成员函数,或者范围的开始和结束迭代器必须可以通过ADL分别使用表达式begin(__range)end(__range)shared_ptr或包含数组的unique_ptr都不满足这些条件。

除非你有充分的理由不这样做,否则你应该使用std::vector<std::string>,这样可以省去分别跟踪数组长度的麻烦。如果在编译时知道数组的长度,std::array<std::string, N>>也是另一种选择。

答案 1 :(得分:2)

在C ++ 17中,为operator[]link)定义了shared_ptr<T[]>。在此之前,这里是unique_ptr的地方,但不是shared_ptr的地方。

因此,以下代码将起作用。

std::shared_ptr<string[]> sp(new string[3]);
    sp[0] = "John";
    sp[1] = "Paul";
    sp[2] = "Mary";

    for(int i =0; i< 3; i++)
    {
        cout<<sp[i]<<"\n";
    }

请注意,它是为shared_ptr<T[]>而不是shared_ptr<T>定义的,即当您具有动态分配的数组时。我还删除了您的自定义删除器,因为您的自定义删除器类似于编译器将使用的默认删除器,但是您可以随意添加它。

对于第二个查询-能够使用新的C ++进行循环(基于范围的循环),您不能直接使用此智能指针,因为基于范围的for循环仅适用于具有begin(),{{ 1}},end()operator++operator*()定义(link)。 最简单的方法是使用具有预分配大小的std :: vector。例如。 operator!=vector<T> sp(3)。这将与您的智能指针方法一样有效。要获得基础内存,可以使用vector<T> sp; sp.reserve(3)例如。 vector<T>::data()。这将为您提供3个元素(通常为n个元素)的动态C数组。

答案 2 :(得分:1)

  

如何索引C ++ shared_ptr / unique_ptr数组?

您已经展示了unique_ptr的代码。

适用于shared_ptr

std::shared_ptr<string> sp( new string[3], []( string *p ) { delete[] p; } );
sp.get()[0] = "string 1";
sp.get()[1] = "string 2";
sp.get()[2] = "string 3";