创建对象向量时,不为每个对象唯一地调用默认对象构造函数

Posted

技术标签:

【中文标题】创建对象向量时,不为每个对象唯一地调用默认对象构造函数【英文标题】:Call not default object constructor for each object uniquely when creating a vector of objects 【发布时间】:2018-06-13 10:50:52 【问题描述】:

我正在尝试创建一个对象向量,并希望为向量中的每个对象唯一地调用非默认构造函数。下面我有一个简化的例子。

在我的示例中,我有一个具有两个构造函数的对象,默认(无参数)和非默认(1 个参数)。当我使用默认构造函数 (v1) 初始化大小为 10 的向量时,构造函数被调用 10 次(从随机数可以看出)。但是,当我尝试使用对象非默认构造函数 (v2) 初始化向量时,对象构造函数被调用一次,并且该对象被复制到向量中的其余元素(x 不再是许多不同的随机数)。

是否可以初始化一个包含 N 个对象的向量,以便为每个对象调用每个对象的非默认构造函数?

示例代码:

#include <vector>
#include <iostream>
#include <cstdlib>

struct Obj 
    int x;

    Obj() 
        x = rand() % 5;
    

    Obj(int max_x) 
        x = rand() % max_x;
    
;

int main() 
    std::vector<Obj> v1(10);     // Default constructor
    std::vector<Obj> v2(10, 5);  // Non-Default Constructor

    for(int i=0; i<10; ++i) 
        std::cout << v1[i].x << ", " << v2[i].x << std::endl;
    

输出:

3, 2
1, 2
2, 2
0, 2
3, 2
0, 2
1, 2
2, 2
4, 2
1, 2

解决方案

以下函数可用于返回一个对象向量,其中调用每个对象的非默认构造函数。

template <typename T, typename ... Args>  std::vector<T> InitVector(const int n, Args ... args) 
     std::vector<T> vec;
     for(int i = 0; i < n; ++i) 
         vec.emplace_back(args ...);
     
     return vec;

【问题讨论】:

统一初始化,是的。 你考虑过srand(time(NULL))吗? 我不太确定这是否是一个解决方案,但您可以重载复制构造函数来执行预期的构造。 (这个观察对我来说是新的。必须深入挖掘它可能成为我们这边的问题......) 不要使用rand(),查看&lt;random&gt; Obligatory link 补充@Qubit 的评论,尽管与实际问题无关。 【参考方案1】:

这里有两种解决方法。

    使用list initialization。

    std::vector<Obj> v25, 5, 5, ...; 
    

    稍后使用emplace_back 插入元素。

    std::vector<Obj> v2;
    v2.reserve(10);
    for (int i=0; i<10; ++i) 
        v2.emplace_back(5);
    
    

【讨论】:

【参考方案2】:

我不太确定这是否是一个解决方案,但您可以重载复制构造函数来执行预期的构造。

我尝试了重载复制构造函数的想法:

#include <vector>
#include <iostream>
#include <cstdlib>

struct Obj 
    const int max_x;
    int x;

    Obj(): Obj(5)  

    Obj(int max_x): max_x(max_x), x(rand() % max_x)  

    Obj(const Obj &obj): Obj(obj.max_x)  
;

int main() 
    std::vector<Obj> v1(10);     // Default constructor
    std::vector<Obj> v2(10, 5);  // Non-Default Constructor

    for(int i=0; i<10; ++i) 
        std::cout << v1[i].x << ", " << v2[i].x << std::endl;
    

输出:

3, 2
1, 0
2, 4
0, 3
3, 1
0, 0
1, 1
2, 2
4, 1
1, 1

Live Demo on coliru

这更好,但缺点是struct Obj 中的附加成员。 :-(

【讨论】:

【参考方案3】:

你可以使用generate_n:

#include <algorithm>
#include <iterator>
std::vector<Obj> v2;
std::generate_n(std::back_inserter(v2),10, []()return 5;);

【讨论】:

【参考方案4】:

感谢所有快速回复。最后,针对我的特定问题的最佳解决方案是创建一个向量初始化函数(按照人们的建议使用 emplace_back),该函数将返回所需的结果。我需要初始化很多对象向量,并且希望它们是不可变的,所以这个通用解决方案可能最适合我的用例。

 #include <vector>
 #include <iostream>
 #include <cstdlib>

 template <typename T, typename ... Args>
 std::vector<T> InitVector(const int n, Args ... args) 
     std::vector<T> vec;
     for(int i = 0; i < n; ++i) 
         vec.emplace_back(args ...);
     
     return vec;
 

 struct Obj 
     int x;

     Obj() 
         x = rand() % 5;
     

     Obj(int max_x) 
         x = rand() % max_x;
     
 ;

 int main() 
     const std::vector<Obj> v1(10);
     const std::vector<Obj> v2 = InitVector<Obj>(10, 5);

     for(int i=0; i<10; ++i) 
         std::cout << v1[i].x << ", " << v2[i].x << std::endl;
     
 

结果:

3, 2
1, 2
2, 0
0, 4
3, 3
0, 1
1, 0
2, 1
4, 2
1, 1

【讨论】:

【参考方案5】:

我认为这些行可以帮助你

std::vector<Obj> v2;
for(int i = 0;i<10;i++)

    Obj s(5); // Non-Default Constructor
   v2.push_back(s); 

【讨论】:

这个答案可能不会获得支持,因为您使用的是 push_back 而不是 emplace_back 并且没有预先保留已知数量的元素。

以上是关于创建对象向量时,不为每个对象唯一地调用默认对象构造函数的主要内容,如果未能解决你的问题,请参考以下文章

删除向量的元素

面向对象

在c++中创建了类,但在创建新对象时,编译显示:不存在默认构造函数

php面向对象编程之构造方法__construct()

用向量 c++ 中的指针成员初始化对象

java对象初始化