让我们看一下表达式模板的一个特殊优点:ET可用于避免在重载运算符中出现的内存中的矢量大小临时值,如:
template<typename T>
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b)
{
std::vector<T> tmp; // vector-sized temporary
for_each(...);
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,此函数的return语句应用移动语义.没有矢量的副本.这是一场胜利.
但是,如果我看一个像这样的简单表达式
d = a + b + c;
Run Code Online (Sandbox Code Playgroud)
我看到上面的函数被调用两次(两者都有operator+),而最后的赋值可以用移动语义来完成.
总共执行2个循环.意思是我把一个临时的,然后读回来.对于大向量,这不属于缓存.这比表达模板更糟糕.他们可以在一个循环中完成整个过程.ET可以执行上述代码,相当于:
for(int i=0 ; i < vec_length ; ++i)
d[i] = a[i] + b[i] + c[i];
Run Code Online (Sandbox Code Playgroud)
我想知道lambdas与移动语义或任何其他新功能一起是否可以像ET一样好.有什么想法吗?
编辑:
基本上,使用ET技术,编译器构建一个解析树,类似于代数表达式和它的类型系统.该树由内部节点和叶子节点组成.内部节点表示操作(加法,乘法等),叶节点表示对数据对象的引用.
我尝试以堆栈计算机的方式考虑整个计算过程:从操作堆栈中获取操作并从参数堆栈中提取下一个参数并评估操作.将结果放回堆栈等待操作.
为了表示这两个不同的对象(操作堆栈和数据叶堆栈),我将一个捆绑在一起std::tuple用于操作,一个
捆绑在一起std::tuple用于数据std::pair<>.最初我使用了a std:vector但导致了运行时开销.
整个过程分为两个阶段:堆栈机器初始化,其中初始化操作和参数堆栈.以及通过将配对的容器分配给向量来触发的评估阶段.
我创建了一个Vec包含私有array<int,5>(有效负载)的类,它具有一个带有"表达式"的重载赋值运算符.
operator*对于所有拍摄Vec和"表达"的组合,全局都会超负荷,
以便在我们不仅仅是的情况下也能正确处理a*b.(注意,我将这个教育示例转换为乘法 - 基本上是为了快速发现imull汇编程序.) …
可能重复:
从模板函数调用的模板类的C++模板成员函数
template<class T1>
class A
{
public:
template<class T0>
void foo() const {}
};
template<class T0,class T1>
void bar( const A<T1>& b )
{
b.foo<T0>(); // This throws " expected primary-expression before ‘>’ token"
}
Run Code Online (Sandbox Code Playgroud)
我可以改成它
b->A<T1>::template foo<T0>();
Run Code Online (Sandbox Code Playgroud)
编译好.不过我也可以改成它
b.A<T1>::template foo<T0>();
Run Code Online (Sandbox Code Playgroud)
编译也很好.是吗?
如何在原始代码的意义上正确调用模板成员函数?
考虑:
std::tuple<int , const A&> func (const A& a)
{
return std::make_tuple( 0 , std::ref(a) );
}
Run Code Online (Sandbox Code Playgroud)
是否std::ref需要编写正确且可移植的代码?(没有它就编译好了)
背景:
如果我删除std::ref我的代码生成没有任何警告(g++-4.6 -Wall),但没有正确运行.
如有兴趣,可定义A:
struct A {
std::array<int,2> vec;
typedef int type_t;
template<typename... OPs,typename... VALs>
A& operator=(const std::pair< std::tuple<VALs...> , std::tuple<OPs...> >& e) {
for( int i = 0 ; i < vec.size() ; ++i ) {
vec[i] = eval( extract(i,e.first) , e.second );
}
}
};
Run Code Online (Sandbox Code Playgroud) 在Linux系统上,我试图通过调用在运行时调用程序system().系统调用以不等于零的返回码退出.
调用WEXITSTATUS错误代码给出"127".
根据系统的手册页,此代码表示/bin/sh无法调用:
如果/bin/sh无法执行,退出状态将是执行命令的退出状态exit(127).
我查了一下:/bin/sh是一个链接bash.bash在那儿.我可以从shell执行它.
现在,我怎么才能找出/bin/sh无法调用的原因?任何内核历史或什么?
编辑:
在这个过程非常有用的提示(见下文)之后strace -f -p <PID>.这是我在system通话中得到的:
Process 16080 detached
[pid 11779] <... select resumed> ) = ? ERESTARTNOHAND (To be restarted)
[pid 11774] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 127}], 0, NULL) = 16080
[pid 11779] --- SIGCHLD (Child exited) @ 0 (0) ---
[pid 11779] rt_sigaction(SIGCHLD, {0x2ae0ff898ae2, [CHLD], SA_RESTORER|SA_RESTART, 0x32dd2302d0}, <unfinished …Run Code Online (Sandbox Code Playgroud) 可以为静态数组的定义提供初始化列表.例:
int main()
{
int int_static[2] = {1,2};
}
Run Code Online (Sandbox Code Playgroud)
动态数组是否可以使用类似的初始化列表?
int main()
{
int* int_ptr = new int[2];
}
Run Code Online (Sandbox Code Playgroud)
这更接近我想要做的事情:
struct foo
{
foo(){}
foo(void * ptr): ptr_(ptr) {}
void * ptr_;
};
int main()
{
foo* foo_ptr = new foo[10];
}
Run Code Online (Sandbox Code Playgroud)
在初始化时,不应该调用默认构造函数,而是调用foo:foo(void*).
对于动态数组的静态初始化程序列表而言,如果加速器核心的实时编译只有有限的堆栈可用,但同时用(加速器编译时间=主机运行时间)静态初始化列表.
我假设没有(因为这需要编译器生成额外的代码,即将参数的值复制到堆位置).我认为c ++ 0x支持其中一些,但我无法使用它.现在我可以使用这样的结构.也许有人知道一招
最好!
我正在分析我的Cuda 4程序,结果发现在某个阶段,运行过程使用了超过80 GiB的虚拟内存.这比我预期的要多得多.在检查了内存映射随时间的演变并比较它正在执行的代码行之后,结果发现在这些简单的指令之后虚拟内存使用量突然超过80 GiB:
int deviceCount;
cudaGetDeviceCount(&deviceCount);
if (deviceCount == 0) {
perror("No devices supporting CUDA");
}
Run Code Online (Sandbox Code Playgroud)
显然,这是第一个Cuda调用,因此运行时已初始化.在此之后,内存映射看起来像(截断):
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 89796 14716 0 r-x-- prg
0000000005db1000 12 12 8 rw--- prg
0000000005db4000 80 76 76 rw--- [ anon ]
0000000007343000 39192 37492 37492 rw--- [ anon ]
0000000200000000 4608 0 0 ----- [ anon ]
0000000200480000 1536 1536 1536 rw--- [ anon ]
0000000200600000 83879936 0 0 ----- [ anon ]
Run Code Online (Sandbox Code Playgroud)
现在将这个巨大的内存区域映射到虚拟内存空间.
好吧,它可能不是一个大问题,因为除非你实际写入这个内存,否则在Linux中保留/分配内存并没有太大作用.但它真的很烦人,因为例如MPI作业必须使用作业可用的最大vmem指定.而对于Cuda工作而言,80GiB只是一个较低的边界 - 一个人也必须添加所有其他东西. …
说,我使用MPI运行并行程序.执行命令
mpirun -n 8 -npernode 2 <prg>
Run Code Online (Sandbox Code Playgroud)
总共启动了8个流程.这是每个节点2个进程和总共4个节点.(OpenMPI 1.5).节点包含1个CPU(双核),节点之间的网络互连是InfiniBand.
现在,可以确定等级编号(或过程编号)
int myrank;
MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
Run Code Online (Sandbox Code Playgroud)
这将返回0到7之间的数字.
但是,如何确定节点编号(在本例中为0到3之间的数字)和节点内的进程编号(0到1之间的编号)?
我想用两个创建一个复合类型enum classes.
enum class Color {RED, GREEN, BLUE};
enum class Shape {SQUARE, CIRCLE, TRIANGLE};
class Object {
Color color;
Shape shape;
public:
};
Run Code Online (Sandbox Code Playgroud)
为了Object在STL容器中使用,std::map<>我需要重载less-than运算符.但是,为了将两个枚举类压缩成一个线性索引,我不知何故需要枚举类的元素数(NoE):
friend bool operator< (const Object &lhs, const Object &rhs) {
return NoE(Shape)*lhs.color+lhs.shape < NoE(Shape)*rhs.color+rhs.shape;
}
Run Code Online (Sandbox Code Playgroud)
如果不以一种很好的方式在程序中的两个位置输入相同的信息(元素数量),怎么做呢?(好的方式意味着没有FIRST_ELEMENT, LAST_ELEMENT,预处理器魔术等)
问题(枚举中的元素数量)类似但未解决enum classes.
我想知道在C++ 11中实现这种复合类型的最佳方法是什么.枚举类定义是否足够强大,还是有必要说:?
enum class Color {RED=0, GREEN=1, BLUE=2};
enum class Shape {SQUARE=0, CIRCLE=1, TRIANGLE=2};
Run Code Online (Sandbox Code Playgroud) 只是输入一个函数会导致分段错误的原因是什么?
输入的功能如下:
21: void eesu3(Matrix & iQ)
22: {
Run Code Online (Sandbox Code Playgroud)
这里Matrix是一个struct.使用GDB运行时,回溯会产生:
(gdb) backtrace
#0 eesu3 (iQ=...) at /home/.../eesu3.cc:22
#1 ...
Run Code Online (Sandbox Code Playgroud)
GDB没有透露具体是什么iQ.在...字面上有.什么可能导致这个?
海湾合作委员会:(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3
程序内置 -O3 -g
来电者喜欢:
Matrix q;
// do some stuff with q
eesu3(q);
Run Code Online (Sandbox Code Playgroud)
这里没什么特别的
我用valgrind重新编写程序:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes <prgname>
Run Code Online (Sandbox Code Playgroud)
输出:
==2240== Warning: client switching stacks? SP change: 0x7fef7ef68 --> 0x7fe5e3000
==2240== to suppress, use: --max-stackframe=10076008 or greater
==2240== Invalid write of size 8
==2240== at 0x14C765B: eesu3( …Run Code Online (Sandbox Code Playgroud) 我想用来objcopy将二进制形式的文本文件包含到可执行文件中.(在运行时我需要将文件作为字符串).这工作正常,直到链接器需要从符号名称中查找引用.问题是objcopy在符号名称前加上文件的路径名.由于我使用GNU Autotools发送包,这个前置路径名发生了变化,我不知道在C/C++程序中使用什么外部链接器符号.
nm libtest.a |grep textfile
textfile.o:
00001d21 D _binary__home_git_textfile_end
00001d21 A _binary__home_git_textfile_size
00000000 D _binary__home_git_textfile_start
Run Code Online (Sandbox Code Playgroud)
libtest.a 是用(从Makefile.am中提取)生成的:
SUFFIXES = .txt
.txt.$(OBJEXT):
objcopy --input binary --output elf32-i386 --binary-architecture i386 $< $@
Run Code Online (Sandbox Code Playgroud)
我怎样才能告诉objcopy我们文件名的词干作为链接符号?或者还有另一种解决问题的方法吗?