关于C++中返回的容器:指针VS非指针

Regarding returning containers in C++: pointer VS non-pointer

本文关键字:指针 VS C++ 返回 关于      更新时间:2023-10-16

我需要弄清楚这一点。下面的代码在这里:

vector<unsigned long long int> getAllNumbersInString(string line){
    vector<unsigned long long int> v;   
    string word;
    stringstream stream(line);
    unsigned long long int num;
    while(getline(stream, word, ',')){
    num = atol(word.c_str());
    v.push_back(num);
    }
    return v;
}

此示例代码只是将输入字符串转换为存储在vector中的一系列无符号长整型。

在上面的这种情况下,如果我有另一个函数调用这个函数,并且我们在向量中似乎有大约100000个元素,这是否意味着,当我们返回它时,将创建一个新的向量,并且将创建与函数中相同的元素,然后函数中的原始向量将在返回时被消除?到目前为止我的理解正确吗?

通常,我会以这样一种方式编写代码,即当涉及到容器时,所有函数都会返回指针,然而,从程序设计的角度来看,根据我上面的理解,在涉及到容器时,我们是否应该始终返回指针?

std::vector很可能(如果启用编译器优化)直接在函数的返回值中构造。这被称为复制/移动省略,是允许编译器进行的优化:

在具有类返回类型的函数中的返回语句中,当表达式是与函数返回类型具有相同cv不合格类型的非易失性自动对象(函数或catch子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作

此报价取自C++11标准,但与C++03类似。需要注意的是,复制/移动省略根本不必发生,这完全取决于编译器。大多数现代编译器都可以毫无问题地处理您的示例。

如果省略没有发生,C++11仍将为您提供比C++03:更进一步的好处

  • 在C++03中,如果没有复制省略,像这样返回std::vector将涉及到,正如您所说,将所有元素复制到返回的对象,然后销毁本地std::vector

  • 在C++11中,std::vector移出函数。移动允许返回的std::vector窃取即将销毁的std::vector的内容。这比复制内容要高效得多。

    你可能已经预料到对象会被复制,因为它是一个左值,但有一条特殊的规则可以让像这样的复制首先被视为移动:

    当满足省略复制操作的标准[…]并且要复制的对象由左值指定时,首先执行重载解析以选择复制的构造函数,就好像对象由右值指定一样。

至于你是否应该返回一个指向容器的指针:答案几乎肯定是否定的。除非完全必要,否则你不应该传递指针。当必要时,你最好使用智能指针。正如我们所看到的,在您的情况下,这根本没有必要,因为通过值传递它几乎没有开销。

使用任何合理的编译器按值返回是安全的,我认为更可取。C++标准允许复制省略,在这种情况下,命名返回值优化(NRVO),这意味着您担心的额外复制不会发生。

请注意,这是一种允许修改程序可观察行为的优化情况。

注2。正如在其他答案中所提到的,C++11引入了移动语义,这意味着,在RVO不适用的情况下,您可能仍然有一个非常便宜的操作,将返回的对象的内容传输给调用者。在std::vector的情况下,这是非常便宜的。但请记住,并非所有类型都可以移动。

您的理解是正确的
但是编译器可以通过RVO和NRVO应用副本省略,并删除正在生成的额外副本。

当指针指向容器时,我们是否应该始终返回指针

若可以的话,当然应该避免按值重新运行,尤其是对于非POD类型。

这取决于您是否需要引用语义。

通常,如果您不需要引用语义,我会说您不应该使用指针,因为在C++11中,容器类支持移动语义,所以按值返回集合很快。此外,编译器可以省略对移动构造函数的调用(这被称为命名返回值优化或NRVO),这样就不会引入任何开销。

但是,如果您确实需要创建集合的独立、一致的视图(即别名),以便在共享该向量所有权的几个地方"看到"对返回向量的插入,那么您应该考虑返回智能指针。