C++,如何从迭代器返回对成员变量的引用

Posted

技术标签:

【中文标题】C++,如何从迭代器返回对成员变量的引用【英文标题】:C++ , how to return a reference to the member variable from iterator 【发布时间】:2012-12-03 16:35:15 【问题描述】:

从 std::vector 派生出以下 B 类

class B: public std::vector <unsigned int>

    public:
            B() : std::vector <unsigned int> ( 0 ) 
;

还有一个A类如下:

class A

    private:        
            B b;    
    double x;

public:
    B & getB () return b;
    B const & getB() const return b;

    bool operator() ( const A & a ) const
            
                    return a < a.x;
            
;

为什么不可能从其迭代器返回对存储在 std::list 中的某个对象 A 的变量 b 的引用(以及如何做到这一点)?

int main ()

std::set <A > alist;
std::set <A> ::iterator i_alist = alist.begin();

for (; i_alist != alist.end(); i_list++)

    B &il = (*i_alist).getB(); //Compiler error
    B &il2 = i_alist->getB(); //Compiler error

    il.push_back(10);   //Modify il and concurrently B

 

编译器错误:

Error   1   error C2440: 'initializing' : cannot convert from 'const B' to 'B &'    d:\test.cpp

感谢您的帮助...

编辑问题

使用 const_cast 的可能解决方案:

B &il2 = const_cast <B&> ( i_alist->getB() );

【问题讨论】:

【参考方案1】:

这与std::vector 关系不大,而与std::set 关系密切。您将对象存储在std::set 中。 std::set 的元素不能从外部修改。一旦将元素插入到集合中,就无法更改它。

出于这个原因,std::set::iterator 可能(并且将)评估为一个常量对象,即使它不是 const_iterator(语言规范实际上允许 std::set::iteratorstd::set::const_iterator 引用相同的类型,但不需要它)。 IE。在您的示例中,*i_listconst A 类型的 const 限定对象。编译器将调用getBconst 版本,它返回const B &amp;。您显然希望突破这种 constness,期望调用 getB 的非 const 版本。

没有办法绕过它,除非您决定使用某种 hack(const_cast 等)从 set 元素中删除 const 性,从而使编译器调用非 const 版本的 getB

基于const_cast 的破解解决方案看起来像

B &il = const_cast<A &>(*i_alist).getB();

或者您可以稍后从返回的B 引用中删除常量

B &il = const_cast<B &>((*i_alist).getB());
B &il2 = const_cast<B &>(i_alist->getB());

【讨论】:

就我个人而言,我认为 C++ 标准强制 set 键上的常量是一个错误。我经常在一个集合中有复杂的对象,它们的内容可以在不影响排序的情况下更改。这不是 C++11 引入的变化吗? @AndreyT:有什么办法可以让存储在 std::set 中的对象从外部被修改?例如使用 const_cast? @Mark Ransom:关键的常量是有道理的,但是修改对象的非关键部分的需求确实经常出现。是的,我同意,设置元素应该是可修改的。 @MarkRansom,但std::set 如何保证您的更改不会影响订购? @aleguna:它不会(可能是调试实现中的一些断言)。它只会说“知道自己在做什么,并自担风险”。【参考方案2】:

您的示例有些地方看起来很奇怪:

    永远不要从std::vector 派生。它不是为这种用途而设计的。通常没有理由这样做,除了懒惰,即避免打字。 A::operator() 是干什么用的?为您正在使用的std::set 提供比较器似乎有些奇怪。通常你不会仅仅因为你把它塞进std::set某处就改变一个类。如果您真的希望能够比较您的 A(通常,不仅仅是为了集合),然后写一个适当的免费 bool operator&lt;(A const&amp;, A const&amp;); 如果它只是为了集合,请在您使用集合的地方编写一个自定义比较器。 (该比较器不应该需要访问 A 的私人信息) A::x 是做什么用的?仅用于比较还是仅用于集合内的比较?如果只是这样,请考虑使用std::map&lt;double, A&gt; 甚至std::map&lt;double, B&gt;,在其中将 x 作为键,将实际对象作为值。

你看,我问了很多未解决的问题,也许解决方案(使用地图)甚至不适合你的问题。那是因为您没有向我们展示您拥有的真实代码,而只是向我们展示了一些名称毫无意义的示例。因此,我们只看到您尝试的工作,而不是您真正想用您的代码实现的内容。

PS:也许你一开始甚至不需要一个有序的容器,将所有的对象都塞进std::vector然后std::sort就足够了。取决于您真正拥有的对象类型(您的示例中的 A 复制/交换成本很低)以及您使用容器的方式 - 插入如何与循环交错等等。

【讨论】:

以上是关于C++,如何从迭代器返回对成员变量的引用的主要内容,如果未能解决你的问题,请参考以下文章

[C++] 智能指针的引用计数如何实现?—— 所有该类的对象共享静态类成员变量

成员变量包含引用类型(c++常问问题七)

C++list类模拟实现

C++ 静态成员变量的引用

C++,成员函数返回对包含指向 const 对象的指针的向量的 const 引用

C++ 静态成员变量的引用