给定此类型进行测试:
struct Counter
{
static int count;
Counter(int)
{
count++;
}
Counter(const Counter&)
{
count++;
}
Counter(Counter&&) noexcept
{
}
};
int Counter::count = 0;
假设我们有以下内容:
std::vector<Counter> vec(5, 0);
根据VS2015,创建了6个Counter
对象。我知道只有 5 个永久对象。为什么编译器不从构造函数参数中放置对象,或者将临时对象移动到第一个位置,然后从中复制其余的对象?
即使 vector 的初始大小设置为 0,仍然会创建 1 个对象。
std::vector<Counter> vec(0, 0);
如果大小直到运行时才知道并且通常为 0(无操作)并且容器中的类型复制或构造成本高昂,那么这一点可能很重要。
在一条语句中初始化 vector 通常很方便,特别是当它们是初始化列表中的类成员或常量时。我怎样才能像下面的代码一样有效地做到这一点:
std::vector<Counter> vec;
vec.reserve(size);
for (size_t i = 0; i < size; i++)
{
vec.emplace_back(0);
}
它仅构造与 vector 中存储的对象一样多的包含对象。
最佳答案
您可以简单地定义一个函数,按照您想要的方式创建 vector 。
作为一个函数,初始化代码是异常安全的。
#include <iostream>
#include <vector>
#include <stddef.h> // ptrdiff_t
#include <utility> // std::forward
using namespace std;
struct Counter
{
static int n_constructor_calls;
Counter( int )
{
++n_constructor_calls;
}
Counter( Counter const& )
{
++n_constructor_calls;
}
Counter( Counter&& ) noexcept
{
++n_constructor_calls;
}
};
int Counter::n_constructor_calls = 0;
//--------------------------------------
using Size = ptrdiff_t;
using Index = Size;
template< class Item, class... Args >
auto make_vector( Size const n, Args&&... args )
-> vector<Item>
{
vector<Item> result;
result.reserve( n );
for( Index i = 0; i < n; ++i )
{
result.emplace_back( forward<Args>( args )... );
}
return result;
}
auto main() -> int
{
auto vec = make_vector<Counter>( 5, 42 );
cout << Counter::n_constructor_calls << " constructor calls.\n";
}
(这输出“5 个构造函数调用。”)
您本质上会问,为什么没有定义 vector
构造函数来执行此操作,
” Why doesn't the compiler emplace the objects from the constructor parameters, or move the temporary object into the first position and then copy the rest from it?
原因之一是该构造函数是在 C++11 中引入移动语义之前定义的。
相对于现有的非常庞大的 C++ 代码库而言,引入额外的构造函数(这会更改重载行为)或更改现有构造函数的行为的成本高昂。
关于c++ - 有效地用初始值初始化 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33335659/