定义生成元素向量C ++的函数时正确的方法是啥

Posted

技术标签:

【中文标题】定义生成元素向量C ++的函数时正确的方法是啥【英文标题】:What is the correct approach while defining a function that generates a vector of elements C++定义生成元素向量C ++的函数时正确的方法是什么 【发布时间】:2014-04-14 23:34:41 【问题描述】:

我必须在 C++ 中定义一个函数来生成类 Foo 的向量并返回它。

我可以用不同的方式定义它,它们都是相当的:

C风格参数传递:

void generateFooVector(vector<Foo> * result)

    for (int i = 0; i < 100; i++)
    
        Foo f = Foo();
        result->push_back(f);
    

int main()


    vector<Foo> result;
    generateFooVector(&result);

参考传递传递:

void generateFooVector(vector<Foo> & result)

    for (int i = 0; i < 100; i++)
    
        Foo f = Foo();
        result->push_back(f);
    

int main()

    vector<Foo> result;
    generateFooVector(result);

实例化向量并返回指针:

vector<Foo> * generateFooVector()

    vector<Foo> * result = new vector<Foo>();
    for (int i = 0; i < 100; i++)
    
        Foo f = Foo();
        result->push_back(f);
    
    return result;

int main()

    vector<Foo> * result = generateFooVector();

C 风格的传递和实例化 Foo 类:

void generateFooVector(vector<Foo *> * result)

    for (int i = 0; i < 100; i++)
    
        Foo * f = new Foo();
        result->push_back(f);
    

int main()

    vector<Foo *> result;
    generateFooVector(&result);

引用传递 + Foo 实例:

void generateFooVector(vector<Foo *> & result)

    for (int i = 0; i < 100; i++)
    
        Foo * f = new Foo();
        result->push_back(f);
    

int main()


    vector<Foo *> result;
    generateFooVector(result);

Vector 实例 + Foo 实例:

vector<Foo*> * generateFooVector()

    vector<Foo*> * result = new vector<Foo*>();
    for (int i = 0; i < 100; i++)
    
        Foo * f = new Foo();
        result->push_back(f);
    
    return result;

int main()


    vector<Foo *> * result = generateFooVector();

按值传递:

vector<Foo> generateFooVector()

    vector<Foo> result;
    for (int i = 0; i < 100; i++)
    
        Foo f = Foo();
        result->push_back(f);
    
    return result;

int main()


    vector<Foo > result = generateFooVector();

也许还有很多其他的解决方案。

所有当前的方式在范围内如何分配内存都有不同的含义。

也许我缺乏理论,但我真的很困惑如何确定每个用例的更好选择,以及为什么一个比另一个更好。你能帮帮我吗?

【问题讨论】:

注意:使用std::generate how to "return an object" in C++ 的可能重复项 一百个push_backs?你听说过resize 和fill吗? @Tacet,或reservestd::back_inserter。如果您每次都需要调用该函数,std::fill 就没有用了,但这里可能就是这种情况。 @chris 我知道这很重要,但这只是一个例子。那不是重点。我在问如何返回元素集合。 【参考方案1】:

我确实看到了两个主要的不同实现 - vector&lt;Foo*&gt;vector&lt;Foo&gt;。其他都是参数传递的变种。

如您所知,vector 在添加时复制元素,在删除vector 时调用元素析构函数。因此,在vector&lt;Foo*&gt; 的情况下,您要避免复制对象,如果对象非常大,这些对象可能会增加。 但是你有责任删除记忆。所以最好存储带有自动删除功能的智能指针,比如vector&lt;shared_ptr&lt;Foo&gt;&gt;vector&lt;unique_ptr&lt;Foo&gt;&gt;(这里需要移动逻辑)。指针的类型取决于您的应用程序逻辑。

顺便说一句,

 Foo* pFoo = new Foo;  // also default constructor call

(你知道the difference 和new Foo() 吗?)

 vector<Foo> v(n);  // init vector with n Foo objects calling default ctor 

【讨论】:

【参考方案2】:

该函数已在标准库中定义,称为std::vector&lt;Foo&gt; 的构造函数。您可以将其称为(C++11 风格)

auto v = std::vector<Foo>(n); // create n default constructed Foo() objects

或以 C++98 风格(在 C++11 中也有效)为

std::vector<Foo> v(n); 

我不会尝试包装这个。

首先,您不想在其中隐藏像 100 这样的幻数,而不是在参数列表(模板或运行时)中隐藏。 不包装构造函数的另一个原因是为了避免读者混淆。如果我遇到generateVector 函数,第一个问题是:“与普通的构造函数调用相比,这个函数是否做了其他/额外的事情?”

【讨论】:

好的,但是auto 的意义何在?实例化对象的“正常”方式有什么好处吗? 他为 C++11 推荐的 Sutter's AAA(几乎总是自动)风格。一个优点是所有变量声明/定义都具有相同的从左到右的形式。 是的,我知道 AAA。但在这种情况下,它看起来像是一种反模式。 @juanchopanza 我认为反模式太强了,因为没有效率损失或任何东西,而只是可读性问题。无论如何,我更新以反映旧样式在 C++11 中仍然有效。 我想这需要一些时间来适应,或者会被丢弃。但它确实对类型提出了额外的要求:它必须是可复制的或可移动复制的。【参考方案3】:

我认为这在很大程度上取决于实际使用情况——最关键的是 foo 有多重? 如果 foo 是轻量级对象和类似 POD 的类型,那么我会使用

Vector<Foo> generateFoo();

否则可能是这样的:

Vector<Foo*> generateFoo();

可能更有用。

标准类型是高效的,并且最喜欢被复制,因此它们对 vector* 解决方案的优势不大。 一般来说,返回(或使用)需要稍后删除的原始指针可能是不明智的——在这种架构中很容易产生泄漏。所以也许看看你的 foo 对象的各种智能指针选项。

【讨论】:

这种指针/智能指针方法无缘无故地让事情变得过于复杂。 如果 foo 是一个大的或昂贵的对象(比如一个打开的文件缓冲区),那么你必须使用某种指针(因为复制是不切实际的)。 不,因为副本很可能会被忽略。所以你应该只玩复杂的指针技巧如果你的编译器/平台不能执行复制省略和如果你没有便宜的移动构造函数。【参考方案4】:

我可能会采用上面采用的参考传递方法。

通常在 C 和 C++ 中,您不希望返回需要稍后释放的对象,因为这可能会导致泄漏。

【讨论】:

【参考方案5】:

做事

vector<Foo> generateFooVector()

    return vector<Foo>(100);

它叫modern c++

【讨论】:

有史以来最佳答案长度与问题长度之比。 它甚至不是现代的。复制省略一直是标准,编译器从 1962 年就开始支持它。 由于移动语义,这在 C++11 中可能没问题,但在 C++99 中可能会出现问题,因为需要在返回时进行复制。 hm,幻数 100 不是接口的一部分,应该是运行时参数 @doron 否,除非您的编译器/平台不支持 RVO。

以上是关于定义生成元素向量C ++的函数时正确的方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

重载比较符号“<”时,在C++中升序排序的正确方法是啥

matlab中怎么定义一个5*6的矩阵,矩阵元素全为c?

在 C# Visual Studio 中更改表单元素名称的正确方法是啥?

c+学习记录

tidyr 扩展函数在预期紧凑向量时生成稀疏矩阵

java中 调用native方法,生成头文件时,为啥不正确?