在Qt 5.2.1中,以下代码结果如何不同?
QVector<int> c;
if (c.cbegin() != c.begin())
{
std::cout << "Argh!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这打印"argh",但以下没有.
QVector<int> c;
if (c.begin() != c.cbegin())
{
std::cout << "Argh!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
请注意,cbegin和begin位置已切换.但是如果你更改容器状态我的意思是例如push_back中的东西,它可以正常工作.在我调用容器上的任何可变方法之前,cbegin和cend都是无效的.这是一个错误或功能吗?
Pra*_*ian 22
你观察到的行为与调用的顺序正在为做QVector::begin
和QVector::cbegin
.如果对前者的调用发生在对后者的调用之前,那么它们的返回值比较相等,但如果你颠倒顺序,它们就不会比较相等.这可以通过以下代码演示:
QVector<int> c;
std::cout << static_cast<void const *>(c.begin()) << std::endl;
std::cout << static_cast<void const *>(c.cbegin()) << std::endl;
Run Code Online (Sandbox Code Playgroud)
打印的地址是相同的.但是,如果交换两个打印语句的顺序,则地址将不同.
如果你深入研究两个成员函数的源代码,你会看到
inline iterator begin() { detach(); return d->begin(); }
inline const_iterator cbegin() const { return d->constBegin(); }
Run Code Online (Sandbox Code Playgroud)
而追溯进一步,两者的机构d->begin()
和d->constBegin()
是相同的.所以区别在于QVector::detach()
第一种情况下的调用.这被定义为
template <typename T>
void QVector<T>::detach()
{
if (!isDetached()) {
#if QT_SUPPORTS(UNSHARABLE_CONTAINERS)
if (!d->alloc)
d = Data::unsharableEmpty();
else
#endif
reallocData(d->size, int(d->alloc));
}
Q_ASSERT(isDetached());
}
Run Code Online (Sandbox Code Playgroud)
可以在此处找到有关正在发生的事情的说明.
隐式共享Qt的容器 - 复制对象时,只复制指向数据的指针.修改对象后,它首先会创建数据的深层副本,以便它不会影响其他对象.创建当天的深层副本的过程称为detach
因为STL样式的迭代器在概念上只是指针,它们直接修改底层数据.因此,非const迭代器在使用时会分离,Container::begin()
以便其他隐式共享实例不会受到更改的影响.
因此,如果调用首先QVector::begin()
发生,则重新分配容器的底层存储,并且后续调用QVector::cbegin()
将返回相同的指针.但是,QVector::cbegin()
在发生任何重新分配之前,将它们反向并调用以返回指向共享存储的指针.
您使用的测试代码与2012年提交的错误报告非常相似.它被关闭为无效,因为
不应该比较constBegin和begin.永远.这根本不是正确的用法(并且可以通过严格的迭代器检查来捕获),所以这里没有什么可以修复的.
这是真的.但是这个函数begin()
被重载了
QVector<T>::iterator QVector::begin();
QVector<T>::const_iterator QVector::begin() const;
Run Code Online (Sandbox Code Playgroud)
这是一个未指定的bevahior,因为未指定 C++ 运算符的操作数的评估顺序==
.在C++中没有从左到右或从右到左评估的概念.
因此,根据编译器和优化,您将iterator
得到begin或const_iterator
version的版本.
归档时间: |
|
查看次数: |
1605 次 |
最近记录: |