【问题标题】:Unnecessary object copy - C++ STL不必要的对象复制 - C++ STL
【发布时间】:2014-02-26 23:28:24
【问题描述】:

伙计们,我正在使用标准模板语言,几个月前我开始阅读有关它的更多信息,并实施了一些练习。我这里有这段代码:

class Student {
// many attributes and methods here plus:
char* name; // Student name
char* courseName; // Student course name
std::string toString() { return std::string(name); }
}

std::string FindCourseName ( std::list< Student > stu, string name )
{
    for ( std::list< Student >::iterator it = stu.begin();
    it != stu.end();
    it++ )
    {
            if ( (*it).toString() == name )
            {
                return it->courseName;
            }
    }
return "";
}

练习要求:

a) 在 FindCourseName 方法中完成了多少不必要的对象创建/复制? b) 您将如何减少此份数? c) 你会如何优化上面的代码?

这段代码我看了很多遍,看不到任何不必要的对象副本,你们能给我点灯吗?哈哈哈非常感谢!

【问题讨论】:

  • 一目了然,我看到至少有 4 个(将列表算作一个。)
  • 嗯,我只看到了 3 个。我还看到了一些严格不需要的副本,但我不会删除它们。
  • @MooingDuck 其实我同意。 3 个绝对可以避免的。
  • 几个,但函数参数类型是唯一值得担心的变化。 (一个小技巧:在表达式 it++ 中有两个轻量级对象的副本。)
  • @aschepler:我当然希望没有人会数那个,这太微不足道了,我怀疑有人会数它。不过家庭作业......也许教授可能会。

标签: c++ stl


【解决方案1】:
  1. 由于这两个函数参数是按值捕获的,所以stuname 都是传入的东西的副本。这很糟糕。
  2. (*it).toString()it-&gt;name 复制为string,但这值得商榷,因为strings 非常方便,而且很难搞砸,所以这种事情很常见。
  3. it++ 返回增量之前的副本,但大多数人不计算它,因为它的优化是如此微不足道。
  4. 在 C++03 中,return std::string(name); 可以有时创建名称的附加临时字符串副本。这主要是理论上的,所以很少有人算这个。
  5. 由于FindCourseName 返回string,它会将返回值复制为string,但同样,这是值得商榷的,因为strings 很好。

【讨论】:

  • 1.哦,这是我不记得的事实,在这种情况下,最好通过引用传递参数,对吧?我在 Java 的 OO 编程中学到了这一点,不知道 C++ 的规则是一样的。关于其他副本,尽管它们都是常见的或理论上的,但我认为这可以算数。感谢您的帮助!
  • 好吧,如果你想要一份副本,请逐份传递。如果需要改变原来的,通过引用传递,否则通过const引用传递。请记住,在将 Java 概念翻译成 C++ 时,所有 Java 变量都是 C++ 指针,而 Java 通过值/副本传递这些指针。
【解决方案2】:

如果类本身不能被改变,并且它的所有数据成员都是私有的,除非在函数类方法中使用,我会根据赋值的要求重写函数如下。

std::string FindCourseName ( const std::list< Student > &stu, const string &name )
{
    for ( std::list< Student >::const_iterator it = stu.cbegin(), last = stu.cend();
    it != last;
    ++it )
    {
            if ( (*it).toString() == name )
            {
                return it->courseName;
            }
    }
return "";
}

如果数据成员名称是公开的,那么我会写

            if ( (*it).name == name )
            {
                return it->courseName;
            }

虽然由于优化和复制/移动构造函数省略没有大的区别。

【讨论】:

  • 我想你在循环中忘记了 it++。应该是 ++it。
  • @VladfromMoscow:为什么你认为班级本身可能不会改变?我没有从问题中得到答案。
  • @Mooing Duck 如果它们不是私有的,那么我认为定义一个类和重复方法没有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
  • 2014-06-30
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 2019-05-27
  • 2019-01-24
相关资源
最近更新 更多