在第二个到最后一个元素之后执行循环并停止的最优雅方式是什么(在C++ 11中)?
注意:我的意思是双向迭代器; 随机访问迭代器是一个微不足道的特例,当然,因为它们有+和-运算符.
std::list<double> x{1,2,3,4,5,6};
for (auto iter = x.begin(); iter != x.end(); ++iter) {
auto iter2 = iter;
++iter2;
if (iter2 == x.end()) break;
std::cout << *iter << std::endl;
}
Run Code Online (Sandbox Code Playgroud) 根据javadoc ... Collections.fill()编写如下:
public static <T> void fill(List<? super T> list, T obj) {
int size = list.size();
if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
for (int i=0; i<size; i++)
list.set(i, obj);
} else {
ListIterator<? super T> itr = list.listIterator();
for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
}
}
Run Code Online (Sandbox Code Playgroud)
很容易理解他们为什么不使用listIterator
if (size < FILL_THRESHOLD || list instanceof RandomAccess)
Run Code Online (Sandbox Code Playgroud)
条件为RandomAccess.但是size < FILL_THRESHOLD上面的使用是什么?
我的意思是使用iteratorfor size>=FILL_THRESHOLD而不是for for 有任何显着的性能优势size < FILL_THRESHOLD吗?
我也看到了Collections.copy()的相同方法: …
是否有一个迭代器的标准实现(意思是stdlib或boost)包装另一个迭代器并且只给出它的每个第n个元素?
我首先想到的是,使用拟合谓词和boost :: filter_iterator是可能的,但是谓词只获取值而不是基本迭代器,所以它无法告诉起始距离.
编辑
提供更多信息:迭代器应与std::transform或等函数兼容std::copy.所以它应该像stdlib迭代器一样使用.
考虑下面第一个代码片段中的代码C++,我得到第二个代码段中指示的编译错误.看起来我在遍历矢量实例时做错了.你能告诉我如何克服这些编译问题吗?谢谢.代码中标记了LINE 171.
SNIPPET 1(代码)
#include <string>
#include <vector>
#include <iterator>
class VipAddressSetEntity : BaseEntity
{
public:
VipAddressSetEntity() : BaseEntity() { }
VipAddressSetEntity(std::string &uuid, std::string &name) : BaseEntity(uuid, name) { }
VipAddressSetEntity(const VipAddressSetEntity ©in)
{
setUUID(copyin.getUUID());
setName(copyin.getName());
std::vector<VipAddressEntity>::iterator iter;
/* LINE 171 is the following*/
for( iter = copyin.mVipAddressList.begin(); iter != copyin.mVipAddressList.end(); iter++ )
{
addVipAddress(*iter);
}
}
VipAddressSetEntity operator = (const VipAddressSetEntity &rhs)
{
setUUID(rhs.getUUID());
setName(rhs.getName());
std::vector<VipAddressEntity>::iterator iter;
for( iter = rhs.mVipAddressList.begin(); iter != rhs.mVipAddressList.end(); iter++ )
{
addVipAddress(*iter);
} …Run Code Online (Sandbox Code Playgroud) void replace(vector<string> my_vector_2, string old, string replacement){
vector<string>::iterator it;
for (it = my_vector_2.begin(); it != my_vector_2.end(); ++it){
if (*it==old){
my_vector_2.erase(it);
my_vector_2.insert(it,replacement);
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以,我希望这个函数用字符串替换替换向量中所有出现的字符串old.但是在调用此函数时,根本不会更改向量.我不确定我是否正确使用擦除和插入功能.有任何想法吗?
根据大多数C++引用,例如cplusplus.com,前向迭代器不需要是可赋值的(我的意思是,引用左值).但是,对于需要写入值的几个STL算法std::fill(例如std::generate等),规范使用了前向迭代器:
template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val);
Run Code Online (Sandbox Code Playgroud)
而等效行为需要左值取消引用:
template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val)
{
while (first != last) {
*first = val;
++first;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,它实际上是使用一个可变的前向迭代器和一次传递.
现在的问题是:
(1)为什么不明确这些情况下使用的前向迭代器是否可变?
(2)更新:我发现以下问题是愚蠢的:我暂时忘记了输出迭代器不需要支持相等比较.无论如何,上述问题仍然存在.
为什么使用前向迭代器,而不是输出迭代器std::fill,std::generate等等,而他们实际上并不需要多遍?(std::copy例如,只需要输出迭代器.基本原理是什么?)
我只是学习C++而我正在使用Accelerated C++.
在向量示例中,编写器使用以下代码;
typedef vector<double>::size_type vec_sz;
vec_sz size = homework.size;
Run Code Online (Sandbox Code Playgroud)
我知道typedef vector<double>::size_type vec_sz;是这样他不必写下一个命令vector<double>::size_type size = homework.size;,但我的问题是为什么他不是只是声明size为整数?
int size = homework.size;
Run Code Online (Sandbox Code Playgroud)
这是因为我们正在使用向量吗?
如果是这样,这是否意味着向量迭代器返回的值不能存储在常规变量中?
请考虑以下最小示例:
#include <functional>
#include <algorithm>
#include <list>
int main() {
std::list<std::function<void()>> list;
list.push_back([&list](){ list.push_back([](){ throw; }); });
std::for_each(list.cbegin(), list.cend(), [](auto &&f) { f(); });
}
Run Code Online (Sandbox Code Playgroud)
它在运行时编译并抛出异常.
我的猜测是只有第一个lambda被执行std::for_each,但显然我错了:如果我在列表的末尾添加另一个lambda,迭代也会达到lambda.
让我们恢复示例(push_front而不是push_back和crbegin/ crend而不是cbegin/ cend):
#include <functional>
#include <algorithm>
#include <list>
int main() {
std::list<std::function<void()>> list;
list.push_front([&list](){ list.push_front([](){ throw; }); });
std::for_each(list.crbegin(), list.crend(), [](auto &&f) { f(); });
}
Run Code Online (Sandbox Code Playgroud)
由于前面的例子,我预计这也会编译和崩溃.
相反,它编译并且不会崩溃.这次,不执行推到列表前面的功能.
问题很简单:这是正确的吗?
为什么两个例子如此违反直觉?
在第一种情况下,我期待一些不同的东西,我错了,这不是问题.
无论如何,我希望两个循环之间的一致性.我的意思是,第二个函数在一个案例中执行,而在另一个案例中不执行,但我在两种情况下都是从开始到结束迭代.
我的推理出了什么问题?
std::set_intersection允许我std::set通过输出元素到输出迭代器来检索两个实例之间的所有共同元素.在我的特殊情况下,我只想检查两组是否有任何共同的元素.
我目前的解决方案是使用如下boost::function_output_iterator设置bool变量:
bool b{false};
set_intersection(begin(s0), end(s0),
begin(s1), end(s1),
make_function_output_iterator([&](const auto&){ b = true; }));
return b;
Run Code Online (Sandbox Code Playgroud)
不幸的是,如果找到匹配项,此解决方案不会提前返回:必须完全遍历集合(即没有提前返回/短路).
是否可以set_intersection提前退货?我能想到的唯一解决方案是从function_output_iterator 函数对象中抛出异常,这是一个可怕的想法.
如果没有,标准库中还有什么可以帮助我,还是我被迫重新实现set_intersection?额外的问题:set_intersection如果它允许提前终止(即标准库算法可能具有的"最通用"接口),界面会如何?
我试图实现一个反序列化方法,它接受一个输入迭代器并执行一系列块读取(使用std::copy和std::copy_n).像这样的东西(只是一个例子):
template <class InputIt>
InputIt unserialize(InputIt it)
{
std::copy_n(it, sizeof(header_type), reinterpret_cast<char*>(&header));
std::copy_n(it, header.payload_size, std::back_inserter(payload));
it = optional.unserialize(it);
return it;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下如何提前输入迭代器,以便每次跟随调用std::copy_n继续从中读取并最终返回它?
出于性能原因,我希望对迭代器类别(尤其是RandomAccessIterator和InputIterator)具有通用性,并希望可以使用std::copy方法而无需重写这些方法.像绑定检查这样的东西将由迭代器适配器完成,或者如果已知大小,则在反序列化调用之前检查.
什么不起作用也不可接受:
std::copy_n<InputIt&>(it, ...)可能适用于某些类别但不适用于所有类别,并且它太不可靠.std::advance在每次调用之后使用会导致为某些迭代器重新读取相同的块.不是优选的,对某些来源可能是不可能的.UPDATE使得迭代器引用适配器没有帮助,因为随机访问迭代器版本的copy_n返回指针超过复制的最后一个元素,而输入迭代器版本返回指向复制的最后一个元素的指针.所以我想自己的版本copy_n最适合使用额外的迭代器适配器进行绑定检查.