STL 集合的解引用迭代器

Posted

技术标签:

【中文标题】STL 集合的解引用迭代器【英文标题】:dereferencing iterator of STL set 【发布时间】:2013-06-22 15:16:54 【问题描述】:

我在从 STL 集继承时遇到问题(我认为):

这是 Prime 类:

class Prime : public set<A> 
private:
  // private data members.
public:
  // C'tor...
  void printParticularA(const int& id);

这里是A类:

class A : public List<B>  
private:  
  // data members.  
  int id;
public:  
  // C'tor  
  A(const A& copy) : List<B>(copy), //copy data members  
      // validate data and throw exceptions if needed. ;

  bool operator< (const A& rhs) const  
    return id < rhs.id;  
  

  void printReport() const   
    for(const B& item : *this) item.print(); 
  


现在问题来了。在下一个函数中,我想打印集合中的特定 A 对象:

void Prime::printParticularA(const int& id) 
  find(AFinder(id))->printReport();

我也试过这个:

void Prime::printParticularA(const int& id) 
  *(find(AFinder(id))).printReport();

注意:假设 B 类有 print() 方法。 注意 2:AFinder 是一个仅使用 id 数据制作虚拟 A 对象的类。

问题在于,当“find”找到对象时,它返回 const_iterator(因为 set 中的每个对象都是 const),而当我取消引用它时,我得到了对象的副本 (??) 但里面的 B 列表是空的! '->' 版本也会出现这种情况。

现在我知道 set 不允许我更改对象,但我不打算更改对象(如您在 printReport 成员函数的声明中所见)。

感谢您对此提供的任何帮助!

编辑:谢谢大家,你们帮了我很多,尤其是学会了不该做的事情。 我解决了这个问题,但它不在集合、列表中,也没有我在这里展示的任何课程。 我的错误在于理解给我的问题(是的,这是我的家庭作业,我还是 C++ 新手)。 抱歉,如果您觉得我浪费了您的时间。 我希望我可以从您的所有经验中学习,并有朝一日帮助他人! 简而言之,谢谢! :)

【问题讨论】:

从 STL 容器继承是个坏主意:***.com/questions/2034916/… 标准容器不是为公共继承而设计的。 您确定find() 成功了吗?您应该始终检查返回值,并且只有在它是 != end() 时才取消引用它。 我确信 find() 成功了。我检查了返回值(尽管上面写了)。 @Anycorn 假设我已经处理了链接中提到的“删除”问题,为什么这段代码不起作用? find() 返回一个 A 对象(肯定),但它的列表是空的。顺便说一句,列表不是 STL,它是我对列表容器的实现。 【参考方案1】:

您的代码几乎一团糟。而且这个问题看起来并不直接与 set 或 iterator 相关,而是一般的坏事。

对于初学者来说,让你的 op

所有这些都可能使您描述的问题消失,如果没有,请发布一个完整的可编译示例,其中包含您所看到的和您期望的正确文本。

【讨论】:

这是我的错,但我没有在这里写所有的代码。 op 到底为什么要验证复制 ctor 中的数据?它只是创建了输入的副本,如果那是无效的,那么你应该在它之前就抛出这个副本。 仍然,复制 c'tor 不是这里的问题。即使我使用默认的,我仍然遇到这个问题。【参考方案2】:

您的代码确实违反了 C++ 的许多规则。你为什么不这样尝试:

#include <iostream>
#include <list>
#include <map>

using namespace std;

class SimpleInt 
public:  
  int data_;

  SimpleInt(const int data): data_(data) ;
  void print() const cout << data_ << " ";;
;

template <typename T>
class A   
private:  
  // private data members.  
public:  
  list<T> list_of_B_; // this is for simlicity. Make getters as you need
  const int id_; // delete it or copy to map. You sholdn't change it.

  A(int id) : list_of_B_(), id_(id)  
  A(const A<T>& copy) : list_of_B_(copy.list_of_B_), id_(copy.id_)  //copy data members  
  A(A<T>&& copy) : list_of_B_(::std::move(copy.list_of_B_)), id_(copy.id_)  //move data members  

  void printReport() const   
    for(const T& item : list_of_B_) item.print(); 
  

;

template <typename T>
class Prime 
private:
  // private data members.
public:
  // The main difference with your source
  map<int, T> map_of_A_; // this is for simlicity. Make getters as you need
  // C'tor...
  void printParticularA(const int& id) 
    auto it = map_of_A_.find(id);
    if (it != map_of_A_.end())
      it->second.printReport();
  
;

int _tmain(int argc, _TCHAR* argv[])

  typedef A<SimpleInt> ASimpled;
  Prime<ASimpled> prime;
  ASimpled a(1);
  a.list_of_B_.push_back(SimleInt(1));
  a.list_of_B_.push_back(SimleInt(2));
  a.list_of_B_.push_back(SimleInt(3));
  ASimpled b(2);
  b.list_of_B_.push_back(SimleInt(10));
  b.list_of_B_.push_back(SimleInt(20));
  b.list_of_B_.push_back(SimleInt(30));
  prime.map_of_A_.insert(make_pair(a.id_, a));
  prime.map_of_A_.insert(make_pair(b.id_, b));

  prime.printParticularA(2);

return 0;

【讨论】:

如果你告诉我我违反了什么规则,我会很高兴,这样我就不会再违反它们了...... 您已经被告知从标准容器继承。 我再次查看您的代码。您在 A 的 ctor 中的问题 - 您没有复制您的 id。因此,在插入 Prime 之后,您的数据被复制并且 id 被破坏。然后找到你没有测试的 return end() 。您尝试取消引用 end() 并获得异常。但无论如何,请将此代码发送到垃圾箱。 ...和_tmain() 违反了标准的哪一部分?售价 3.6.1 美元 我懒得在项目 write'n'forget 中更改它。我可以吗?【参考方案3】:

虽然您没有包含List 的实现,但问题可能就在那里。更准确地说,Listbegin()end() 成员函数可能会被破坏。它们返回的值可能是相同的(或无效的),导致基于范围的 for 循环什么都不做。这当然是基于您的 set::find 返回一个有效的迭代器而不是 end 迭代器。

以下示例是对您问题中代码的修改。它使用std::list 而不是List 并且不使用AFinder,因为您还没有包含它的代码。

#include <set>
#include <list>
#include <iostream>

struct B

    int id_;
    explicit B(int id) : id_(id) 
    void print() const
    
        std::cout << "B::id = " << id_ << std::endl;
    
;

class A : public std::list<B>

public:
    explicit A(int id) : id_(id) 

    bool operator<(const A& rhs) const
    
        return id_ < rhs.id_;
    

    bool operator==(const A& other) const
    
        return id_ == other.id_;
    

    void printReport() const
      
        for(auto& item : *this)
        
            item.print();
        
    

private:  

    // data members.  
    int id_;

;


class Prime : public std::set<A>

public:

    void printParticularA(const int& id)
    
        std::cout << "finding " << id << std::endl;
        auto el = find(A(id));
        if(el == cend())
        
            std::cout << "not found" << std::endl;
        
        else
        
            find(A(id))->printReport();
        
        std::cout << "done finding " << id << std::endl;
    
;


int main()

    Prime p;

    A   a1(1);
    a1.push_back(B(1));
    a1.push_back(B(2));
    a1.push_back(B(3));
    p.insert(a1);

    A   a2(2);
    a2.push_back(B(4));
    a2.push_back(B(5));
    a2.push_back(B(6));
    p.insert(a2);

    p.printParticularA(1);

    p.printParticularA(2);

    // doesn't exit
    p.printParticularA(3);

这会产生以下输出。

找到 1 B::id = 1 B::id = 2 B::id = 3 完成查找 1 发现 2 B::id = 4 B::id = 5 B::id = 6 完成查找 2 发现 3 没找到 找到了 3

【讨论】:

以上是关于STL 集合的解引用迭代器的主要内容,如果未能解决你的问题,请参考以下文章

取消引用集合迭代器时将“字符串&”绑定到“常量字符串”时出错

stl迭代器失效

迭代器模式

C++ STL 基础及应用 迭代器

STL——容器(deque) 元素的存取&迭代器

集合框架与迭代器