【问题标题】:How can i avoid output parameters while doing backtracking?回溯时如何避免输出参数?
【发布时间】:2013-08-22 19:51:46
【问题描述】:

我们知道输出参数真的很糟糕

 void foo(set<int> *x)

这里的 x 实际上是预期的参数,这在 Linux 系统调用中很常见。 但是对于 c++ 来说,这似乎不是一个好的编码习惯。

我有一个场景,我必须回溯一个字符串列表,并从每个列表中返回所有可能的字符串组合。

 a b 
 d e 
 f g
 Possible combinations are:
    a d f, a d g, a e f, a e g, etc...

list<list<string> > parameters;

一个简单的回溯解决方案是:

    void  getCombinations(list<list<string> > &param, 
          list<list<string> >::iterator it, 
          vector<string> &backtracker, 
          list<vector<string> > &output){

          if(it == param.end()){
              output.append(backtracker);
          }
          for(auto i = it->begin; i!= it->end(); i++){
            backtracker.push_back(*i);
             getCombinations(param, it+1, backtracker, output)
            backtracker.pop_back();
          }
         }

现在,我怎样才能在这里避免输出参数,以便我可以返回输出列表?

【问题讨论】:

  • 我们知道输出参数真的很糟糕 是吗?你能进一步解释你所说的那句话是什么意思吗?你所说的输出参数,为什么不好?
  • 这方面已经有很长的讨论了,你可以参考stackoverflow.com/questions/18157090/…了解更多!!!
  • 所以输出参数的意思是通过可修改的引用或指针传递,对吗?无论如何,虽然在许多情况下有一些理由更喜欢按值返回,但这并不意味着输出参数是不可信的。你仍然可以使用它们,如果在你的设计中它是有意义的并且你已经有了它的实现,那就使用它。有些地方输出参数是由编码指南强制(例如,以 C++03 编译器为目标的商店)
  • 是的,你是正确的!谢谢

标签: c++ backtracking rvo


【解决方案1】:

据我所知,输出参数是一种很好的做法,具体取决于您在做什么。这就是指针或引用的用途。这就是 java 或 C# 默认使用对象引用的原因。更好的性能,更容易使用等等。

编辑:如果你真的想这样做,你可以使用 const 引用作为输出参数。只要它是一个 const 引用,即使在代码中调用了引用对象的析构函数,它也会保持活动状态。

您还可以像前面所说的那样正确定义副本、移动构造函数(这意味着您需要在列表上创建一个包装类)。

【讨论】:

  • 指针通常不好(除非封装得很好),这是 C++ 没有 java 或 C#(顺便说一句:C# 和 java 有指针,只有)
  • ...除了一些值类
  • 可用功能并不能让它变得更好。这可能是相当主观的,但我觉得在函数声明中明确声明输出参数比检查正在使用的类的构造函数更容易遵循。就我而言,我更喜欢你所做的方式,我觉得大多数程序员都有同样的感觉。我只是觉得这些特性让 c++ 越来越像 perl,它变得越来越像 perl,只是为了让代码看起来更好,而不是更容易理解。至于指针,这就是为什么通常使用引用更好。
  • 这并不是说即使调用了析构函数,对象仍然保持活动状态,而是将临时对象的生命周期延长到绑定它的引用的生命周期。
【解决方案2】:

输出参数在 C++ 中一直显示。但是,您可以使用方法封装输出数据结构。

class ComboGenerator {
public:
  void getCombinations(list<list<string> > &param, 
    list<list<string> >::iterator it, 
    vector<string> &backtracker){

    if(it == param.end()){
      result.append(backtracker);
    }
    for(auto i = it->begin; i!= it->end(); i++){
      backtracker.push_back(*i);
      getCombinations(param, it+1, backtracker)
      backtracker.pop_back();
    }
  }

  list<list<string>> &getResult() { return result; }

private:
  list<list<string>> result;    
};

我的经验是,在 95% 的时间里,有人在谈论实践是出于个人的脾气暴躁。其他 5% 的时间是好的感觉。

【讨论】:

  • 这让我想起了另一个想法。使函数成为类的构造函数并按如下方式使用它:GetCombinations(...).result()。只有在 NRVO 没有发生并且不能依赖移动构造函数的情况下才值得。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 2020-05-05
  • 1970-01-01
  • 1970-01-01
  • 2020-07-29
  • 2019-06-24
  • 2021-06-23
相关资源
最近更新 更多