【问题标题】:what is the correct type for this loop?这个循环的正确类型是什么?
【发布时间】:2011-11-28 20:02:46
【问题描述】:

其中 RoomCentreNodeVectors 是整数向量的向量。 roomKills 是一个整数向量,而 level.Nodes() 返回一个 Node 对象的向量。 Node 对象的 Room() 函数返回和 int。

for (std::vector<std::vector<int>>::size_type i = 0; i < level.RoomCentreNodeVectors().size(); i++)
{
    RoomKills.push_back(level.Nodes()[level.RoomCentreNodeVectors()[i][0]].Room());
}

for (std::vector<int>::size_type i = 0; i < level.RoomCentreNodeVectors().size(); i++)
{
    RoomKills.push_back(level.Nodes()[level.RoomCentreNodeVectors()[i][0]].Room());
}

【问题讨论】:

  • 你不坚持使用迭代器有什么原因吗?
  • 显然,您需要将所有这些东西重构为命名变量。我的眼睛在流血。
  • 我猜是哪个编译的!
  • @R.MartinhoFernandes 因为我想我还没有了解它们。我认为这是正确的,因为 .size() 返回了这些尺寸。
  • @SirYakalot 是的,martinfowler.com/refactoring

标签: c++


【解决方案1】:

简短的回答是您应该使用被索引的向量类型的 size_type。如果 RoomCentreNodeVectors() 返回 int 向量的向量,则您的第一个循环正确指定了类型。它很可能等于 size_t。

剩下的只是回答你的问题,如果你愿意,你可以忽略它。

首先,typedef 将有助于使其更易于阅读。例如

typedef std::vector<Node> NodeVec;
typedef std::vector<int> IntVec;
typedef std::vector<IntVec> IntVecVec;
for (IntVecVec::size_type i = 0; ...

除非 RoomCentreNodeVectors() 的值在此循环期间发生变化,否则我肯定会保存返回值,这样您就不必每次都调用该函数。如果函数返回一个值而不是引用类型,则尤其如此,因为您将在每次循环中复制该向量两次。而且,正如 R. Martinho Fernandes 所提到的,您也可以使用迭代器,并避免整个 size_type 问题:

const IntVecVec& nodeVecs = RoomCentreNodeVectors();
IntVecVec::const_iterator end = nodeVecs .end();
const NodeVec& nodes = level.Nodes(); // if Nodes() doesn't change during loop
for (IntVecVec::const_iterator iter = nodeVecs .begin(); iter != end; ++iter)
{
    const IntVec& vec = *iter;
    int j = vec[0];
    int room = nodes[j].Room();
    RoomKills.push_back(room);
}

【讨论】:

    【解决方案2】:

    两者都是正确的,因为size_type 的实际类型不依赖于模板特化。它通常与size_t 相同,我建议您使用它以获得更好的可读性:

    for (size_t i = 0; i < level.RoomCentreNodeVectors().size(); i++)
    {
        RoomKills.push_back(level.Nodes()[level.RoomCentreNodeVectors()[i][0]].Room());
    }
    

    如果我在代码中看到你的 sn-p,我会重构它。

    【讨论】:

    • 啊好吧,但是为什么它要求你为向量指定一个类型呢?较长的 size_type 和 size_t 有区别吗?
    • @SirYakalot 我不认为它可以保证是一样的,但很可能是一样的。您需要指定 因为您不能使用 vector 否则(或任何模板)。
    • 另见size_t vs container::size_type。我发现this answer 特别有趣。
    【解决方案3】:

    我会将此代码更改为使用迭代器...然后您可以使用 C++11 auto 关键字执行以下操作:

    for(auto iter = begin(level.RoomCentreNodeVectors); iter != end(level.RoomCentreNodeVectors); iter++)
    {
        RoomKills.push_back(level.Nodes()[(*iter)[0]].Room());
    }
    

    【讨论】:

    • 这并没有解决问题。
    • 为什么不呢?他想知道循环的类型是什么,我们使用带有迭代器的 auto 关键字来允许编译器推断该类型,而不是显式指定它。
    • 好的...那么循环的类型是什么(通过它我了解迭代器的类型)?
    • iter 的类型,如果不使用 auto 关键字,将是 std::vector&lt;std::vector&lt;int&gt;&gt;::iterator ... 使用 auto 关键字当然会使这个代码更简单,也更灵活,因为我们没有明确说明类型(即,如果他将来使用向量容器更改某些内容,他将不必更改迭代器的类型)
    • 但他的问题不是迭代器,而是 size_type。明白我的意思了吗?您正在发布新代码,并根据您的代码回答他的问题。此外,这只适用于 C++11
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-30
    相关资源
    最近更新 更多