【问题标题】:std::map::begin() returns an iterator with garbagestd::map::begin() 返回带有垃圾的迭代器
【发布时间】:2013-11-29 03:50:17
【问题描述】:
typedef unsigned long Count;
typedef float Weight;
typedef std::map<std::string, Count> StringToCountMap;
typedef std::map<std::string, Weight> StringToWeightMap;
typedef std::map<unsigned long, StringToCountMap> UnsignedToStringToCountMap;
typedef std::map<unsigned long, StringToWeightMap> UnsignedToStringToWeightMap;

typedef std::map<unsigned long, std::size_t> ClustersMap;


class DefaultClusteringAlgorithm
{
public:
    // minumum number of documents changing clusters for algorithm to end
    static const unsigned DocumentChangeThreshold = 0;

    DefaultClusteringAlgorithm(unsigned numClusters, const UnsignedToStringToWeightMap &documentVectors)
        : numClusters_(numClusters)
        , documentVectors_(documentVectors)
    {
    }

~DefaultClusteringAlgorithm() {}

const ClustersMap &DoClustering();

private:
    void ChooseInitialCentroids();
    unsigned ClusterOnCentroids();
    void RecalculateCentroids();
    float DocumentDotProduct(const StringToWeightMap &left, const StringToWeightMap &right);
    float DocumentLength(const StringToWeightMap &document);

    unsigned numClusters_;

    // stores cluster_id => centroid
    std::vector<StringToWeightMap> centroids_;

    // maps question id => cluster id
    ClustersMap clusters_;

    // document vector
    const UnsignedToStringToWeightMap &documentVectors_;
};

void DefaultClusteringAlgorithm::RecalculateCentroids()
{
    std::vector<unsigned> newCentroidsSizes(centroids_.size());
    std::vector<StringToWeightMap> newCentroids(centroids_.size());

    ClustersMap::const_iterator clusterMapping = clusters_.begin();

    for (; clusterMapping != clusters_.end(); ++clusterMapping)
    {
        std::size_t clusterId = clusterMapping->second;

        ++newCentroidsSizes[clusterId];
        const StringToWeightMap &document = documentVectors_.at(clusterMapping->first);

        StringToWeightMap::const_iterator termWeight = document.cbegin();

        for (; termWeight != document.end(); ++termWeight);
        {
            newCentroids[clusterId][termWeight->first] += termWeight->second;
        }
    }

    std::vector<unsigned>::iterator centroidSize = newCentroidsSizes.begin();

    for (; centroidSize != newCentroidsSizes.end(); ++centroidSize)
    {
        std::size_t clusterId = centroidSize - newCentroidsSizes.begin();

        StringToWeightMap::iterator centroidTermWeight = newCentroids[clusterId].begin();

        for (; centroidTermWeight != newCentroids[clusterId].end(); ++centroidTermWeight)
        {
            centroidTermWeight->second /= *centroidSize;
        }
    }
}

在创建 const_iterator termWeight 时出现问题:

StringToWeightMap::const_iterator termWeight = document.begin();

如上图所示,termWeight const_iterator 包含无效数据。但是,const std::map 文档是完全有效的 std::map。我想不出为什么会发生这种情况。

我最近了解到 std::map::cbegin() 存在。我应该改用那个方法吗?

编辑:包含更多上下文

【问题讨论】:

  • 显示上述内存转储时,将执行哪一行代码?为termWeight 显示的数据在第一次分配的行之后是无效的。
  • cbegin 无济于事。你的代码库中有const_casts 吗?从std::map 中获得非常糟糕的行为的一种方法是在map 的内容位于map 时对其进行重新排序。第二,你在哪条线上?是否发生了任何迭代?还有其他线程吗? documentVectors_的类型是什么?
  • 要执行的下一行是最内层 for 循环中的单行。所以 termWeight 已经被赋值了。
  • 没有其他线程。我将编辑问题以显示 documentVectors_ 的类型
  • 如果你要使用cbegin(),你也应该使用cend()

标签: c++ stdmap bad-alloc const-iterator


【解决方案1】:

哈!我发现了错误!我的 for 循环末尾的一个愚蠢的小分号!

【讨论】:

    【解决方案2】:

    std::map begin() 方法可能会返回一个指向地图末尾的迭代器,因为地图中可能根本没有任何元素。

    【讨论】:

    • 他在 for 循环中检查这种情况,尽管他应该使用 cend() 而不仅仅是 end()
    • 请注意,document 在调试窗口中有一个 size24
    • @JohnSaxton 感谢您指出这一点。我最近将其更改为 cbegin() 并忘记对 cend() 进行适当的更改
    猜你喜欢
    • 2013-03-19
    • 2013-10-25
    • 2020-09-13
    • 2020-07-12
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    相关资源
    最近更新 更多