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::iterator
和 std::set::const_iterator
引用相同的类型,但不需要它)。 IE。在您的示例中,*i_list
是 const A
类型的 const 限定对象。编译器将调用getB
的const
版本,它返回const B &
。您显然希望突破这种 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<(A const&, A const&);
如果它只是为了集合,请在您使用集合的地方编写一个自定义比较器。 (该比较器不应该需要访问 A 的私人信息)
A::x
是做什么用的?仅用于比较还是仅用于集合内的比较?如果只是这样,请考虑使用std::map<double, A>
甚至std::map<double, B>
,在其中将 x 作为键,将实际对象作为值。
你看,我问了很多未解决的问题,也许解决方案(使用地图)甚至不适合你的问题。那是因为您没有向我们展示您拥有的真实代码,而只是向我们展示了一些名称毫无意义的示例。因此,我们只看到您尝试做的工作,而不是您真正想用您的代码实现的内容。
PS:也许你一开始甚至不需要一个有序的容器,将所有的对象都塞进std::vector
然后std::sort
就足够了。取决于您真正拥有的对象类型(您的示例中的 A 复制/交换成本很低)以及您使用容器的方式 - 插入如何与循环交错等等。
【讨论】:
以上是关于C++,如何从迭代器返回对成员变量的引用的主要内容,如果未能解决你的问题,请参考以下文章
[C++] 智能指针的引用计数如何实现?—— 所有该类的对象共享静态类成员变量