下面的代码显示了模板化工厂。它需要一个仿函数类并返回operator()
的返回值。
下面的仿函数类返回一个简单的结构,在这种情况下是巨大的:ints.resize(10000000,0)
。
当我调用这个工厂时,我得到了一个巨大的减速。特别是在经常调用for (size_t i=0,j=10000; i!=j; ++i)
时。我怀疑是按值返回(即使它仅通过引用返回)。
有人可以告诉我如何解决这种减速问题吗?
#include <iostream>
#include <chrono>
#include <vector>
template<typename T, typename... Args>
auto generate_one(Args... args) -> decltype(T{args...}()) {
T t{args...}; // <<---- this is so slow!!!
return t();
}
// template<typename T, typename... Args>
// auto generate_one(Args... args) -> decltype(T{args...}()) {
// auto start = std::chrono::system_clock::now();
// T t{args...};
// auto end = std::chrono::system_clock::now();
// auto elapsed = end - start;
// std::cout << elapsed.count() << '\n';
// return t();
// }
struct product_t
{
std::vector<int> ints;
};
struct initial_product_t
{
product_t operator()()
{
product_t product;
product.ints.resize(10000000,0);
return product;
}
};
struct updated_product_t
{
updated_product_t(product_t & product)
: product(product)
{}
product_t & operator()()
{
return product;
}
product_t & product;
};
int main()
{
auto product = generate_one<initial_product_t>();
for (size_t i=0,j=10000; i!=j; ++i)
{
std::cout << i << "/" << j << std::endl;
product = generate_one<updated_product_t>(product);
}
}
修改1
我在其他用户的建议后尝试了以下代码。但是有一些编译错误。
struct updated_product_t
{
updated_product_t(product_t && product)
: product(product)
{}
product_t operator()()
{
return std::move(product);
}
product_t product;
};
错误
$ clang++ -std=c++14 stackoverflow.cpp -o test
stackoverflow.cpp:60:15: error: no matching function for call to 'generate_one'
product = generate_one<updated_product_t>(product);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
stackoverflow.cpp:6:6: note: candidate template ignored: substitution failure
[with T = updated_product_t, Args = <product_t>]: no matching constructor
for initialization of 'updated_product_t'
auto generate_one(Args... args) -> decltype(T{args...}()) {
^ ~
1 error generated.
我不明白失败的地方。
修改2
我已经改变了 - 深入挖掘左撇子和左撇子后 - 工厂
template<typename T, typename... Args>
auto generate_one(Args&&... args) -> decltype(T{args...}()) {
T t{args...}; // ^^
return t(); // a reference to a lvalue or rvalue
}
我更改了operator()
,因为它现在返回带有std::move
的产品。
struct updated_product_t
{
updated_product_t(product_t & product)
: product(product)
{}
product_t operator()()
{
return std::move(product);
}
product_t & product;
};
通过这些更改,我可以快速执行。
答案 0 :(得分:0)
缓慢就在这里:
product = generate_one<updated_product_t>(product);
每次都在进行大型矢量的分配。这是修复它的一种方法:
int main()
{
product_t product = generate_one<initial_product_t>();
product_t* pp;
for (size_t i=0,j=10000; i!=j; ++i)
{
std::cout << i << "/" << j << std::endl;
pp = &generate_one<updated_product_t>(product);
}
}
或者您可以重构product_t
以保留shared_ptr
以避免复制向量的数据:
struct product_t
{
std::shared_ptr<std::vector<int>> ints;
};
struct initial_product_t
{
product_t operator()()
{
product_t product;
product.ints = std::make_shared<std::vector<int>>(10000000);
return product;
}
};