首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++映射:带有自定义类的operator[]不工作(总是返回0)

C++映射:带有自定义类的operator[]不工作(总是返回0)
EN

Stack Overflow用户
提问于 2020-02-25 23:42:02
回答 2查看 487关注 0票数 0

我正在尝试实现一个MinHeap,其中堆上的对象是WorkerNodes。我的方法返回映射,它的目的是允许客户端代码确定哪些WorkerNode索引已经从minHeapify操作中更改。

代码语言:javascript
复制
std::cout << "heapifying " << heap_[root] << "from index " << root << "\n.";
    int size = heap_.size();
    bool swapped = false;
    std::map<WorkerNode, int> tracker;

    for (int i = root; i >= 0; --i)
    {
        while (true)
        {
            int leftChild = 2 * i + 1;
            if (leftChild < 0 || leftChild >= size)
                break;
            int rightChild = 2 * i + 2;
            int smallerChild = leftChild;
            if (rightChild < size && heap_[rightChild] < heap_[leftChild])
                smallerChild = rightChild;

            if (heap_[i] <= heap_[smallerChild])
                break;

            // index tracking

            tracker[heap_[i]] = smallerChild;
            tracker[heap_[smallerChild]] = i;

            std::cout << "**\n\n"
                      << heap_[i] << " has moved to " << smallerChild;
            std::cout << ", and " << heap_[smallerChild] << " has moved to " << i << "\n**";

            // swap heap_[i] and heap_[smallerChild]
            swapped = true;
            T temp = heap_[i];
            heap_[i] = heap_[smallerChild];
            heap_[smallerChild] = temp;
            i = smallerChild;
        }
    }
    if (!swapped) // avoids bad access
    {
        tracker[heap_[root]] = root;

        for (auto &itm : tracker)
        {
            std::cout << "**\n"
                      << itm.first << " is at " << itm.second << "!!!\n";
        }
        std::cout << "**\nno swap; " << heap_[root] << " stays at " << tracker[heap_[root]] << "\n**";
    }

    return tracker;

下面是我看到的输出:

代码语言:javascript
复制
heapifying W1-1from index 0
.**
W1-1 is at 0!!!
**
no swap; W1-1 stays at 0
**heapifying W2-2from index 1
.**
W2-2 is at 1!!!
**
no swap; W2-2 stays at 0
**heapifying W3-3from index 2
.**
W3-3 is at 2!!!
**
no swap; W3-3 stays at 0
**heapifying W0-3from index 3
.**
W0-3 is at 3!!!
**
no swap; W0-3 stays at 0

在运行测试用例时,我注意到了这个问题,我正在做这样的事情:

代码语言:javascript
复制
WorkerNode key("W4", 2);
    // after two decrements, its index should still be 3.
    BOOST_TEST(tracker[key] == 3);

得到这样的输出:

代码语言:javascript
复制
error: in "minheap_test_suite/case6": check tracker[key] == 3 has failed [0 != 3]

因此,据我所知,我的minHeapify方法中的预退出for循环确认了正确的数据被插入到映射中,但是当我试图使用[]操作符访问这个数据时,它无法找到我刚刚插入的WorkerNode索引配对,返回0作为它可能只是默认构造的值。

刚才我尝试使用find()而不是[]时,如下所示:

代码语言:javascript
复制
tracker[heap_[root]] = root;

        for (auto &itm : tracker)
        {
            std::cout << "**\n"
                      << itm.first << " is at " << itm.second << "!!!\n";
        }
        int index = tracker.find(heap_[root])->second;
        std::cout << "**\nno swap; " << heap_[root] << " stays at " << index << "\n**";

我得到以下输出:

代码语言:javascript
复制
heapifying W1-1from index 0
.**
W1-1 is at 0!!!
**
no swap; W1-1 stays at -1354735968
**heapifying W2-2from index 1
.**
W2-2 is at 1!!!
**
no swap; W2-2 stays at 3233540

这里是我的WorkerNode.h文件,删除了注释:

代码语言:javascript
复制
#include <ostream>
#include <string>

struct WorkerNode
{
    unsigned numJobs_;     ///< worker job count.
    std::string workerID_; ///< worker ID string.

    explicit WorkerNode() : numJobs_(0), workerID_("") {}

    WorkerNode(std::string id) : numJobs_(0), workerID_(id) {}

    WorkerNode(std::string id, unsigned jobs) : numJobs_(jobs), workerID_(id) {}

    WorkerNode(WorkerNode &&other) : numJobs_(other.numJobs_), workerID_(other.workerID_)
    {
        other.numJobs_ = 0;
        other.workerID_ = "";
    }

    WorkerNode(const WorkerNode &other) : numJobs_(other.numJobs_), workerID_(other.workerID_) {}

    WorkerNode &operator=(const WorkerNode &other)
    {
        if (this == &other)
            return *this;
        this->numJobs_ = other.numJobs_;
        this->workerID_ = other.workerID_;
        return *this;
    }

    WorkerNode &operator=(WorkerNode &&other)
    {
        if (this == &other)
            return *this;
        this->numJobs_ = other.numJobs_;
        this->workerID_ = other.workerID_;
        other.numJobs_ = 0;
        other.workerID_ = "";
        return *this;
    }

    ~WorkerNode() {}

    bool operator<(const WorkerNode &rhs) const
    {
        return *this <= rhs;
    }

    bool operator<=(const WorkerNode &rhs) const
    {
        if (numJobs_ < rhs.numJobs_)
            return true;
        else if (rhs.numJobs_ < numJobs_)
            return false;
        else
        {
            return workerID_.compare(rhs.workerID_) <= 0 ? true : false;
        }
    }

    bool operator==(const WorkerNode &rhs) const
    {
        if (numJobs_ == rhs.numJobs_ && workerID_ == rhs.workerID_)
            return true;
        else
        {
            return false;
        }
    }

    void operator--()
    {
        if (numJobs_ > 0)
            numJobs_ -= 1;
    }

    void operator++()
    {
        numJobs_ += 1;
    }

    friend std::ostream &operator<<(std::ostream &out, const WorkerNode &n)
    {
        out << n.workerID_ << "-" << n.numJobs_;
        return out;
    }
};

我是不是做错了?

编辑:

好了伙计们这是我的解释。我对之前的荒谬代码膨胀表示歉意。此示例100%地再现了我当前的混淆。让我们弄清这件事的真相。

Key.h:

代码语言:javascript
复制
// user-defined struct, intended to be used as a map key.

#include <string>
#include <ostream>

struct Key
{
    std::string id;
    unsigned jobs;

    Key(std::string id_ = "", unsigned jobs_ = 0) : id(id_), jobs(jobs_) {}

    bool operator<(const Key &rhs) const
    {
        if (jobs < rhs.jobs)
            return true;
        else if (rhs.jobs < jobs)
            return false;
        else
            return id.compare(rhs.id) <= 0 ? true : false;
    }

    bool operator<=(const Key &rhs) const
    {
        if (jobs < rhs.jobs)
            return true;
        else if (rhs.jobs < jobs)
            return false;
        else
            return id.compare(rhs.id) <= 0 ? true : false;
    }

    friend std::ostream &operator<<(std::ostream &o, const Key &key)
    {
        o << key.id << "-" << key.jobs;
        return o;
    }
};

MinHeap.h:

代码语言:javascript
复制
#include <vector>
#include <map>

#include "Key.h"

struct MinHeap
{
    std::vector<Key> heap;

    std::map<Key, int> minHeapify(int root)
    {
        std::map<Key, int> tracker;
        for (int i = 0; i < heap.size(); ++i)
            tracker[heap[i]] = i;
        return tracker;
    }

    std::map<Key, int> insert(const Key &key)
    {
        heap.push_back(key);
        return minHeapify(heap.size() - 1);
    }
};

main.cpp:

代码语言:javascript
复制
#include <iostream>
#include "MinHeap.h"

int main()
{
    MinHeap heap;
    std::map<Key, int> tracker;
    for (int i = 0; i < 3; ++i)
    {
        Key key("Key" + std::to_string(i), i);
        tracker = heap.insert(key);

        //checking tracker contents using auto for loop
        std::cout << "tracker keyindex contents: ";
        for (auto &itm : tracker)
        {
            std::cout << itm.first << " ::: " << itm.second << ", ";
        }
        std::cout << "\n\n";

        //checking key and tracker[key], which should reflect
        //each other as well as the operation done in minHeapify.

        /// *** what tracker[key] is actually printing ***
        std::cout << "tracker[key] = " << tracker[key] << std::endl;
        /// **********************************************

        /// *** what tracker[key] is expected to be printing ***
        std::cout << "actual tracker key index: " << key.jobs << std::endl;
        /// ****************************************************
    }

    return 0;
}

亲自运行main.cpp。这里的大问题是最后两个打印语句。优先for循环确认minHeapify(int)操作确实返回了预期的密钥,并具有预期的索引。

但是,使用[Key]map<Key,int> 进行子索引的尝试不会返回预期的索引。

希望我能更清楚地说明这种混淆。

提前谢谢你的帮助。

干杯

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-02-26 18:15:36

我认为,这个问题已经在雷米·莱博的评论中找到了。

Key::operator<的实现不符合严格弱序的要求,因为类型需要作为std::map中的键使用。

您需要在实现中做一些小小的更改。

代码语言:javascript
复制
bool operator<(const Key &rhs) const
{
    if (jobs < rhs.jobs)
        return true;
    else if (rhs.jobs < jobs)
        return false;
    else
        return id.compare(rhs.id) <  0 ? true : false; // Needs to be <, not <=
}

您可以使用std::tie简化函数。

代码语言:javascript
复制
bool operator<(const Key &rhs) const
{
   std::tie(jobs, id) < std::tie(rhs.jobs, rhs.id);
}
票数 3
EN

Stack Overflow用户

发布于 2020-02-26 18:18:53

这就是最小可重现性示例的样子:

代码语言:javascript
复制
#include <iostream>
#include <map>

struct Key {
  std::string id;
  unsigned    jobs;
  bool operator<(const Key & rhs) const {
    if (jobs < rhs.jobs)
      return true;
    else if (rhs.jobs < jobs)
      return false;
    else
      return id.compare(rhs.id) <= 0 ? true : false;
  }
};

int main() {
  std::map<Key, int> m;
  m[Key { "Key0", 0 }] = 0;
  m[Key { "Key1", 1 }] = 1;
  m[Key { "Key2", 2 }] = 2;
  std::cout << m[Key { "Key0", 0 }] << std::endl;
  std::cout << m[Key { "Key1", 1 }] << std::endl;
  std::cout << m[Key { "Key2", 2 }] << std::endl;
  return 0;
}

这更容易理解吗?这对人们帮助你更容易吗?

你现在能自己发现问题吗?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60404753

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档