模糊的工厂

时间:2017-03-25 00:21:16

标签: c++ c++11 templates

下面的代码显示了模板化工厂。它需要一个仿函数类并返回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;
};

通过这些更改,我可以快速执行。

1 个答案:

答案 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;
    }
};