在不复制和使用移动语义的情况下初始化向量
Initialize vector without copying and using move semantics
有没有办法在初始化向量时避免复制?
下面的代码将产生以下输出。
#include <iostream>
#include <vector>
using namespace std;
struct Ticker {
std::string m_ticker;
Ticker() {
std::cout << "Default constructor" << std::endl;
}
Ticker(const std::string& ticker)
: m_ticker(ticker)
{
std::cout << "Parametrized constructor" << std::endl;
}
Ticker(Ticker&& other)
{
std::cout << "Move constructor" << std::endl;
m_ticker = other.m_ticker;
other.m_ticker = "";
}
Ticker(const Ticker& x)
{
std::cout << "Copy constructor" << std::endl;
m_ticker = x.m_ticker;
}
~Ticker()
{
std::cout << "Destructor" << std::endl;
}
friend std::ostream& operator << (std::ostream& os, const Ticker& dr);
};
std::ostream& operator << (std::ostream& os, const Ticker& dr)
{
os << "|" << dr.m_ticker << "|";
return os;
}
int main() {
std::vector<Ticker> table = std::move(std::vector<Ticker>{std::move(Ticker("MSFT")), std::move(Ticker("TSL"))});
for (const auto& row: table)
{
std::cout << row << std::endl;
}
return 0;
}
这会产生以下输出:
Parametrized constructor
Move constructor
Parametrized constructor
Move constructor
Copy constructor
Copy constructor
Destructor
Destructor
Destructor
Destructor
|MSFT|
|TSL|
Destructor
Destructor
有没有办法避免复制构造函数并就地初始化或不复制而直接移动?
如果你使用
std::vector<Ticker> table = std::vector<Ticker>{Ticker("MSFT"), Ticker("TSL")};
你会得到
Parametrized constructor
Parametrized constructor
Copy constructor
Copy constructor
Destructor
Destructor
|MSFT|
|TSL|
Destructor
Destructor
其中有 4 个构造函数调用,而不是您当前的 6 个。其中 2 个调用用于 Ticker("MSFT")
和 Ticker("TSL")
,另外两个副本是因为初始化列表将其中的元素存储为 const
,因此必须将它们复制到向量中无法从 const
对象移动。
要获得最少 2 次构造函数调用,您需要使用 emplace_back
成员函数,如
std::vector<Ticker> table; // create empty vector
table.reserve(2); // allocate space for 2 Tickers but create nothing
table.emplace_back("MSFT"); // directly construct from "MSFT" in the reserved space
table.emplace_back("TSL"); // directly construct from "TSL" in the reserved space
其输出为
Parametrized constructor
Parametrized constructor
|MSFT|
|TSL|
Destructor
Destructor
如果你想要像 std::vector<Ticker> table = std::vector<Ticker>{Ticker("MSFT"), Ticker("TSL")};
这样的语法,但没有额外的开销,你可以将 emplace_back
解决方案包装在工厂函数中,如
template <typename T, typename... Args>
auto make_vector(Args&&... args)
{
std::vector<T> data;
data.reserve(sizeof...(Args));
(data.emplace_back(std::forward<Args>(args)), ...);
return data;
}
然后你会像
一样使用它
auto table = make_vector<Ticker>("MSFT", "TSL");
有没有办法在初始化向量时避免复制?
下面的代码将产生以下输出。
#include <iostream>
#include <vector>
using namespace std;
struct Ticker {
std::string m_ticker;
Ticker() {
std::cout << "Default constructor" << std::endl;
}
Ticker(const std::string& ticker)
: m_ticker(ticker)
{
std::cout << "Parametrized constructor" << std::endl;
}
Ticker(Ticker&& other)
{
std::cout << "Move constructor" << std::endl;
m_ticker = other.m_ticker;
other.m_ticker = "";
}
Ticker(const Ticker& x)
{
std::cout << "Copy constructor" << std::endl;
m_ticker = x.m_ticker;
}
~Ticker()
{
std::cout << "Destructor" << std::endl;
}
friend std::ostream& operator << (std::ostream& os, const Ticker& dr);
};
std::ostream& operator << (std::ostream& os, const Ticker& dr)
{
os << "|" << dr.m_ticker << "|";
return os;
}
int main() {
std::vector<Ticker> table = std::move(std::vector<Ticker>{std::move(Ticker("MSFT")), std::move(Ticker("TSL"))});
for (const auto& row: table)
{
std::cout << row << std::endl;
}
return 0;
}
这会产生以下输出:
Parametrized constructor
Move constructor
Parametrized constructor
Move constructor
Copy constructor
Copy constructor
Destructor
Destructor
Destructor
Destructor
|MSFT|
|TSL|
Destructor
Destructor
有没有办法避免复制构造函数并就地初始化或不复制而直接移动?
如果你使用
std::vector<Ticker> table = std::vector<Ticker>{Ticker("MSFT"), Ticker("TSL")};
你会得到
Parametrized constructor
Parametrized constructor
Copy constructor
Copy constructor
Destructor
Destructor
|MSFT|
|TSL|
Destructor
Destructor
其中有 4 个构造函数调用,而不是您当前的 6 个。其中 2 个调用用于 Ticker("MSFT")
和 Ticker("TSL")
,另外两个副本是因为初始化列表将其中的元素存储为 const
,因此必须将它们复制到向量中无法从 const
对象移动。
要获得最少 2 次构造函数调用,您需要使用 emplace_back
成员函数,如
std::vector<Ticker> table; // create empty vector
table.reserve(2); // allocate space for 2 Tickers but create nothing
table.emplace_back("MSFT"); // directly construct from "MSFT" in the reserved space
table.emplace_back("TSL"); // directly construct from "TSL" in the reserved space
其输出为
Parametrized constructor
Parametrized constructor
|MSFT|
|TSL|
Destructor
Destructor
如果你想要像 std::vector<Ticker> table = std::vector<Ticker>{Ticker("MSFT"), Ticker("TSL")};
这样的语法,但没有额外的开销,你可以将 emplace_back
解决方案包装在工厂函数中,如
template <typename T, typename... Args>
auto make_vector(Args&&... args)
{
std::vector<T> data;
data.reserve(sizeof...(Args));
(data.emplace_back(std::forward<Args>(args)), ...);
return data;
}
然后你会像
一样使用它auto table = make_vector<Ticker>("MSFT", "TSL");