【问题标题】:Is there a more efficient way to structure/pattern C++ than this?有没有比这更有效的构造/模式 C++ 的方法?
【发布时间】:2012-01-14 02:41:02
【问题描述】:

基本思想是我有一个“家庭”类,它们都做同样的事情,但方式略有不同。这个“家族”用于“高性能”循环,因此速度至关重要。此外,具体的家庭由配置文件指定...

问题是这里的 main 函数中有大量的代码重复。有没有更好的方法来构建这个,所以我不必写HP<objx> testtest.loop(bobloblaw) 三遍? (实际上,这段代码比 2 行多得多……)

class obj1 {
public:
    double f(double x) const { return 1.; }
};

class obj2 {
public:
    double f(double x) const { return x; }
};

class obj3 {
public:
    double f(double x) const { return x*x; }
};

template <class O>
class HP {
private:
    O obj;

public:

    double loop(const vector<double>& x) {
        double s = 0.;
        for (auto i : x) s += obj.f(i);

    return s;
    }
};

int main() {
    string config = "bob";
    double result = 0;
    vector<double> bobloblaw;

    /* Read configuration file to determine which object to use. */
    if (config == "obj1") {
        HP<obj1> test;
        result = test.loop(bobloblaw);
    } else if (config == "obj2") {
        HP<obj2> test;
        result = test.loop(bobloblaw);
    } else if (config == "obj3") {
        HP<obj3> test;
        result = test.loop(bobloblaw);
    }

    return result;
}

【问题讨论】:

  • +1 供被逮捕的发展参考。

标签: c++


【解决方案1】:

以下内容未经测试,但应该可以:

class obj1
{
public:
  double f(double x) const { return 1.; }
};

class obj2
{
public:
  double f(double x) const { return x; }
};

class obj3
{
public:
  double f(double x) const { return x*x; }
};

class HPbase
{
public:
  virtual double loop(const vector<double>&) = 0;
};

template <class O> class HP:
  public HPbase
{
public:
  double loop(const vector<double>& x)
  {
    double s = 0.;
    for (auto i : x)
      s += obj.f(i);
    return s;
  }
private:
  O obj;
};

std::unordered_map<std::string, std::unique_ptr<HPbase>> decode{
  {"obj1"}, new HP<obj1>()},
  {"obj2"}, new HP<obj2>()},
  {"obj3"}, new HP<obj3>()} };

int main()
{
  string config = "bob";
  double result = 0;
  vector<double> bobloblaw;

  /* Read configuration file to determine which object to use. */
  result = decode[config].loop(bobloblaw);
}

请注意,唯一添加的是 HP&lt;&gt; 的基类和替换代码的 if/else 逻辑的映射。

【讨论】:

  • 谢谢 - 这是完美的,正是我希望得到的答案类型。
  • 为什么是 unordered_map?在这里使用 std::map 不是更好/更快吗?
  • @DavidFeurle:好吧,在这种情况下,这可能根本不重要,因为只有一次查找。但是,通常std::map 查找是 O(log n),而 std::unordered_map 查找是 O(1)。因此,如果您有足够的条目,unordered_map 查找会更快。对于少数条目,我不知道哪个更快(它甚至可能取决于实现),但无论如何,它不太可能成为瓶颈。但是,对于少数条目,std::map 可能更节省内存。
【解决方案2】:

难道你不能让这 3 个类都是具有相同父类的子类吗? main 仍然需要使用正确的子类分配给 test,但 test 本身将被声明为公共超类。

这里的缺点是可能会对性能造成(可能很小)影响,因为编译器在为 test.loop 生成代码时不知道将使用哪个版本,因此必须在运行时决定。

解决此问题的另一种方法是将通用代码编写为宏,因此只编写一次,但扩展为 3 个不同的副本,编译器可以根据测试的变体对每个副本进行优化正在使用。可能会使调试变得很麻烦,但如果您的重点是性能和减少源的冗余(而不是对象的冗余),那可能是一个很好的权衡。

【讨论】:

  • 决定取决于用户输入,所以它总是在运行时完成。
  • 哪一个会被使用是在运行时确定的;但是每个版本要执行的代码是在编译时生成的,所以如果每种类型的子类都有不同的代码版本,编译器可以更好地优化每个版本。
  • +1 建议使用宏,尽管存在危险,但它确实有有效用途。
  • 然而,我会注意到您关于虚拟函数调用(每次迭代)的性能影响“可能很小”的建议是没有根据的——预测性能已经足够困难了 with代码,没有看到代码(或对预期的执行环境一无所知),你甚至没有猜测的基础。
  • @John Bartholomew:我都同意(因为我无法说出开销与方法“胆量”成本的相对大小)和不同意(我有控制权关于如何引入开销,它应该相当于子类型之间的切换,所有这些都是编译器知道的——而且“可能很小”是一个相当薄弱的声明,一开始是:))。
猜你喜欢
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多