我开始使用 Boost ICL,并偶然发现了非常基本的东西。例如,函数contains
应返回 true 或 false,具体取决于给定元素是否在区间内。然而,这适用[right,left]_open_intervals
但不适用[open,closed]_inteval
(参见下面的示例)。
这似乎太明显了,不可能是一个疏忽。我正在以预期的方式使用图书馆吗?
例如(使用 gcc 4.8 或 clang 3.3 和 Boost 1.54):
#include <boost/concept_check.hpp> //needed to make this MWE work, boost icl should include it internally
#include<boost/icl/right_open_interval.hpp>
#include<boost/icl/closed_interval.hpp>
#include<boost/icl/open_interval.hpp>
int main(){
boost::icl::right_open_interval<double> roi(6.,7.);
assert(boost::icl::contains(roi, 6.) == true); //ok
assert(boost::icl::contains(roi, 6.) == false); //ok
boost::icl::closed_interval<double> oi(4.,5.); // or open_interval
assert(boost::icl::contains( oi, 4.) == false); //error: "candidate template ignored"
assert(boost::icl::contains( oi, 5.) == false); //error: "candidate template ignored"
}
Run Code Online (Sandbox Code Playgroud)
注意:以上称为“静态”间隔(因为它们的绑定属性是类型的一部分)。动态间隔按预期工作。
我有以下std::reference_wrapper
用于类型(double
)和用户定义类型(std::string
)的构建.
为什么它们在流运算符的情况下表现不同?
#include<functional> //reference wrapper
#include<iostream>
void fd(double& d){}
void fs(std::string& s){}
int main(){
double D = 5.;
std::reference_wrapper<double> DR(D);
std::cout << "DR = " << DR << std::endl; //ok
fd(DR); // ok
std::string S = "hello";
std::reference_wrapper<std::string> SR(S);
std::cout << "SR = " << static_cast<std::string&>(SR) << std::endl; // ok
std::cout << "SR = " << SR << std::endl; // error: invalid operands to binary expression ('basic_ostream<char, std::char_traits<char> >' and 'std::reference_wrapper<std::string>')
fs(SR); // ok …
Run Code Online (Sandbox Code Playgroud) iostream built-in user-defined-types c++11 reference-wrapper
当我尝试为通用容器(例如std::list<...>
,而不是特定容器,例如std::list<double>
)专门化模板变量时,我收到链接错误gcc 5.3
(但不是clang 3.5
)
/tmp/ccvxFv3R.s: Assembler messages:
/tmp/ccvxFv3R.s:206: Error: symbol `_ZL9separator' is already defined
Run Code Online (Sandbox Code Playgroud)
http://coliru.stacked-crooked.com/a/38f68c782d385bac
#include<string>
#include<iostream>
#include<list>
#include<forward_list>
#include<vector>
template<typename T> std::string const separator = ", ";
template<typename... Ts> std::string const separator<std::list<Ts...> > = "<->";
template<typename... Ts> std::string const separator<std::forward_list<Ts...>> = "->";
int main(){
std::cout << separator<std::vector<double>> << '\n';
std::cout << separator<std::list<double>> << '\n';
std::cout << separator<std::forward_list<double>> << '\n';
}
Run Code Online (Sandbox Code Playgroud)
(这可以很好地编译clang 3.5
并按预期工作。此外,可变参数模板不是导致问题的原因,我尝试使用非可变参数模板)。
如果这不是 中的错误gcc
,您认为有解决方法吗?我尝试使用类专业化,但也不可能:
template<class T>
struct separator{ …
Run Code Online (Sandbox Code Playgroud) 我有一些重复的代码,我从两个流中读取,
{
std::ifstream ifs("A.dat");
... code ...
}
{
std::ifstream ifs("B.dat");
... same code ...
}
Run Code Online (Sandbox Code Playgroud)
我想在一个循环中统一两者.第一反应是这样做:
for(auto ifs : {ifstream("A.dat"), ifstream("B.dat")})
{
... code ...
}
Run Code Online (Sandbox Code Playgroud)
但是它没有编译,因为类型不可复制,所以我尝试了这个:
for(auto& ifs : {ifstream("A.dat"), ifstream("B.dat")})
{
... code ...
}
Run Code Online (Sandbox Code Playgroud)
这是行不通的,因为ifs
在循环内部是const
.(a const ifstream
不能使用.)这也不起作用,我想也是出于同样的原因:
for(auto&& ifs : {ifstream("A.dat"), ifstream("B.dat")})
Run Code Online (Sandbox Code Playgroud)
最后,我最终做到了这一点.
#include<iostream>
int main(){
for(auto& name : {"A.dat", "B.dat"})
{
std::ifstream ifs(name);
... code ...
}
Run Code Online (Sandbox Code Playgroud)
但我仍然很好奇是否有可能直接使用类似的类型std::ifstream
?
在编程元素的第91页中,Stepanov和McJones说Iterator的概念需要一个successor
函数,但这不一定是常规的,因为
......
i = j
并不意味着successor(i) = successor(j)
......
(见在线页面)
我理解converse successor(i) = successor(j)
并不暗示i=j
(例如在两个空终止列表中)并且successor
可能没有为某些输入定义该函数.但我不明白怎么可能i = j
导致这种情况发生successor(i) != successor(j)
.
他们会指的是什么情况?也许某些迭代器会随机(如同)跳跃?或者某个迭代器具有隐藏状态,并且在指向同一个元素之后以不同于其他迭代器的方式"跳转"(并且在此意义上比较相等).
他们立即跳转到需要常规successor
功能的改进(ForwardIterator),所以我不清楚.
最初我认为输入迭代器可以具有此属性.但是,我仍然很难看出这是否构成一个反例:(在STL的某个实施中).
#include <iostream>
#include <sstream>
#include <iterator>
#include <numeric>
#include <cassert>
using std::cout; using std::endl;
int main(){
std::istream_iterator<int> it1(std::cin); // wait for one input
std::istream_iterator<int> it2 = it1;
assert(it1 == it2);
cout << "*it1 = " << *it1 << …
Run Code Online (Sandbox Code Playgroud) 下面是使用很棒的Boost.Serialization库的最小示例。
要编译该库,我需要链接到boost_serialization
预编译的库。
$ c++ -std=c++11 example.cpp -o example.x -lboost_serialization
^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
该库经过大量模板化,尽管内部很复杂,但实际代码(函数体)非常简单。只有少数参考文献需要链接,即:
boost::archive::text_oarchive_impl<boost::archive::text_oarchive>::text_oarchive_impl(std::ostream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::text_iarchive_impl(std::istream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_oarchive>::~text_oarchive_impl()
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::~text_iarchive_impl()
...
boost::archive::archive_exception::~archive_exception()'
Run Code Online (Sandbox Code Playgroud)
是否有可能在不链接为仅标头库的情况下使用该库?
例如一些未记录的技巧或黑客行为?
这将使其在某些超级计算机集群和环境中使用起来更加简单,而在这些环境中,编译 Boost 并不是那么简单。
#include<sstream>
#include<numeric>
#include<boost/archive/text_oarchive.hpp> // needs linking
#include<boost/archive/text_iarchive.hpp>
#include<boost/serialization/vector.hpp>
int main(){
std::vector<double> v(10); std::iota(v.begin(), v.end(), 0);
std::stringstream ss;
{
boost::archive::text_oarchive toa(ss);
toa << v;
}
std::vector<double> v2;
boost::archive::text_iarchive tia(ss);
tia >> v2;
assert(v == v2);
}
Run Code Online (Sandbox Code Playgroud)
编辑:如果库提供仅标头的选项,就像 Boost.Asio 那样(/sf/answers/2851060761/。)
EDIT2:Boost.Serialization 的作者和维护者拒绝了仅将其设为标头的想法。https://github.com/boostorg/serialization/issues/71
我有一个类似指针的结构,代替指针.与指针的区别在于它具有(也是特殊的)分配器可以用来释放内存的额外信息.
这种类似指针的结构适用于所有基本用途.我可以分配和释放内存,dereferrence,increment ->
等.
现在我想使用这个指针由类似STL的容器管理.早期,我意识到STL向量基本上不能处理非原始指针.
T*
太硬编码了,标准基本上排除了任何不是指针的东西.
受Boost.Interprocess的启发' offset_ptr<T>
我决定使用Boost.Container vector
,它是非常可定制的,原则上可以管理任何东西,传递给它的分配器boost::container::vector
可以处理任何类似指针的东西.
现在班上boost::container::vector<T, myallocator_with_special_pointer<T>>
可以做任何事......除了resize()
!!
查看其中的代码boost/container/vector.hpp
似乎调整大小的过程(基本上是分配,然后是复制(或移动)和释放)涉及原始指针.
违规行是:
[line 2729:] T * const new_buf = container_detail::to_raw_pointer
(allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start));
Run Code Online (Sandbox Code Playgroud)
后面是后面的
[line 3022:] this->m_holder.start(new_start); // new_start is the same as new_buf above.
// member ::start(pointer&) will need to convert a raw pointer to the pointer typedef.
Run Code Online (Sandbox Code Playgroud)
两条线都绝对杀死了使用任何不是的东西的可能性raw_pointer
.即使我有一个原始指针的转换运算符,其他有关特殊指针的信息也将丢失.
这个小细节似乎非常愚蠢,禁止使用非原始指针.鉴于容器的所有努力都是通用的(例如,定义pointer
typedef),为什么这部分代码T*
仅用于调整大小?
换句话说,为什么Boost Container不使用这一行
[alternative] pointer const new_buf =
allocator_traits_type::allocate(this->m_holder.alloc(), new_cap, this->m_holder.m_start);
Run Code Online (Sandbox Code Playgroud)
是否有一种变通方法或使用Boost容器向量来处理非原始指针的替代方法? …
在通用代码中,我试图告诉输出迭代器(实际上 astd::back_inserter_iterator
移动一系列元素。令我惊讶的是,它看起来好像元素在 move-to-back_inserter 操作中移动。
#include<algorithm> // move
#include<iterator> // back_inserter
#include<vector>
int main(){
std::vector<std::vector<double> > v(10, std::vector<double>(100));
std::vector<std::vector<double> > w;
assert( not v[0].empty() and w.size() == 0 );
std::copy(v.begin(), v.end(), std::back_inserter(w));
assert( not v[0].empty() and w.size() == 10 );
std::move(v.begin(), v.end(), std::back_inserter(w));
assert( v[0].empty() and w.size() == 20 ); // were v elements moved to w?
}
Run Code Online (Sandbox Code Playgroud)
但是,我认为 的元素不可能v
真正移动到w
,因为毕竟back_inserter
会执行 apush_back
这意味着复制到w
。
在这种std::move
情况下,v
元素似乎更有可能被移动到临时文件中,然后才复制到w
.
那是对的吗?真的有 …
无法比较来自不同容器的迭代器(例如,请参见此处:https : //stackoverflow.com/a/4664519/225186)(或者从技术上讲,它不需要有意义。)
这就提出了另一个问题,来自不同范围的迭代器可以相互分配吗?
Container A = ...;
Container B = ...;
auto it1 = A.begin();
it1 = B.begin(); // it1 first belonged to A, does it1 need to belong to B later
Run Code Online (Sandbox Code Playgroud)
迭代器概念是否需要在某些标准或公认的实践或即将到来的标准范围内工作的最后一行?
由于相等和赋值是如此交织在一起,似乎如果相等 ( ==
) 并不总是很好地定义,那么赋值 ( =
) 也不需要很好地定义,并且可能出于类似的潜在原因。
我问的原因并不纯粹是学术性的,因为某个迭代器实现可能具有来自容器的一些“元数据”,并且(取决于实现)可能会或可能无法重新分配,或者只是重新分配的浪费。(例如,A 独有的步幅信息,与 B 的步幅信息不一致。另一个例子是迭代器存储对原始范围的引用时。)
这可以允许在尝试分配时,特定字段(成员)可能保持不变。在某些情况下可以使分配工作,这可能会产生较少的惊喜,但它也可能限制实现,问题是是否真的有必要定义/允许不同来源(出处)的迭代器之间的分配?
2021 年更新:
链接的文件内容如下:
[...] 术语 == 的域在普通数学意义上用于表示(需要)定义 == 的值集。这个集合可以随着时间的推移而改变。每个算法对其使用的迭代器值的 == 域都提出了额外的要求。这些要求可以从算法对 == 和 != 的使用中推断出来。
所以有一个隐式定义的(由算法) 的有效性范围==
。表述这个问题的另一种方式是,是否==
可以通过简单的逻辑使用,对 的适用范围应用相同的警告=
。
潜在的想法是,==
孤立地定义 …
有没有办法将 CUDA Thrust 库与 Valgrind 内存泄漏检查器一起使用?
我问的原因是因为这个简单的程序:
#include <thrust/device_vector.h>
int main(){
thrust::device_vector<int> D(5);
assert( D.size() == 5 );
}
Run Code Online (Sandbox Code Playgroud)
编译为:
#include <thrust/device_vector.h>
int main(){
thrust::device_vector<int> D(5);
assert( D.size() == 5 );
}
Run Code Online (Sandbox Code Playgroud)
使 Valgrind 相信存在多种可能的内存泄漏。
我知道它们一定是误报,而且 valgrind 不是用来检测 GPU 内存泄漏的,但我想知道是否有一个标志或标准方法可以使这两个工具一起工作(例如检测 CPU 内存泄漏)。
如果有一套标准的 Valgrind 异常,我会很乐意使用它们,但我想在玩 wack-a-mole 之前先问一下。
$ /usr/local/cuda-11.1/bin/nvcc device_vector.cu -o device_vector.cu.x
Run Code Online (Sandbox Code Playgroud)
提到的自述文件README_MISSING_SYSCALL_OR_IOCTL对我来说不是很有帮助。
添加注释:CUDA 附带了一个名为 memchecker 的 memchecker cuda-memcheck
,它不会报告上面程序中的内存泄漏,但它似乎不能替代 valgrind,因为它不会检测简单 cpu 程序中的实际内存泄漏:
#include <thrust/device_vector.h>
int main(){
// thrust::device_vector<int> D(5);
// assert( D.size() == 5 );
// …
Run Code Online (Sandbox Code Playgroud)