我想了解一些关于如何正确思考C++ 11闭包以及std::function
如何实现它们以及如何处理内存的信息.
虽然我不相信过早优化,但我确实习惯在编写新代码时仔细考虑我的选择对性能的影响.我还进行了大量的实时编程,例如微控制器和音频系统,其中要避免非确定性的存储器分配/解除分配暂停.
因此,我想更好地了解何时使用或不使用C++ lambdas.
我目前的理解是没有捕获闭包的lambda就像一个C回调.但是,当通过值或引用捕获环境时,将在堆栈上创建匿名对象.当必须从函数返回值闭包时,将其包装进去std::function
.在这种情况下闭包内存会发生什么?它是从堆栈复制到堆?它是否在被释放时std::function
被释放,即它是否被引用计数为std::shared_ptr
?
我想在实时系统中我可以建立一个lambda函数链,将B作为一个连续参数传递给A,以便A->B
创建一个处理管道.在这种情况下,A和B闭包将被分配一次.虽然我不确定这些是否会在堆栈或堆上分配.然而,一般来说,这在实时系统中使用似乎是安全的.另一方面,如果B构造一些它返回的lambda函数C,那么C的内存将被重复分配和释放,这对于实时使用是不可接受的.
在伪代码中,一个DSP循环,我认为这将是实时安全的.我想执行处理块A然后执行B,其中A调用它的参数.这两个函数都返回std::function
对象,因此f
它将是一个std::function
对象,其环境存储在堆上:
auto f = A(B); // A returns a function which calls B
// Memory for the function returned by A is on the heap?
// Note that A and B may maintain a state
// via mutable value-closure!
for (t=0; t<1000; t++) {
y = f(t)
}
Run Code Online (Sandbox Code Playgroud)
我认为在实时代码中使用它可能很糟糕:
for (t=0; t<1000; t++) {
y = A(B)(t); …
Run Code Online (Sandbox Code Playgroud) 假设我有一个Haskell程序或库,我想让非Haskeller,可能是C程序员可以访问.我可以使用GHC将其编译为C,然后将其作为C源分发吗?
如果可以,有人可以提供一个最小的例子吗?(例如,Makefile)
是否可以使用GHC自动确定所需的编译器标志和标头,然后将其捆绑到一个文件夹中?
基本上我有兴趣能够在C和Haskell中编写部分程序,然后将其作为tarball分发,但不要求目标安装GHC和Cabal.
我正在尝试使用从stdin获取的数据生成两行的绘图.我有一个文件"test.csv":
0,1.1,2
1,2,3
2,6,4
4,4.6,5
5,5,6
Run Code Online (Sandbox Code Playgroud)
我一直试图用这样的命令来绘制这个,
$ cat test | gnuplot -p -e "set datafile separator \",\"; plot '-' using 1:2 with lines, '' using 1:3 with lines;"
Run Code Online (Sandbox Code Playgroud)
但无论我尝试什么,
line 5: warning: Skipping data file with no valid points
Run Code Online (Sandbox Code Playgroud)
我认为这是因为对于第二行,stdin已经用尽了.有没有办法让gnuplot从stdin的每一列中获取不同图的数据?
谢谢.
我正在尝试过滤掉包含特定字符的字符串,但它不起作用.我想make
不支持多种%
模式?
.PHONY: test
test:
echo $(filter-out %g%, seven eight nine ten)
Run Code Online (Sandbox Code Playgroud)
得到:
$ make test
echo seven eight nine ten
seven eight nine ten
Run Code Online (Sandbox Code Playgroud)
它不过滤掉"八"?实际上我想要做的是从包含"$"的文件名列表中过滤掉.(在Java环境中.)
有希望,还是我必须使用$(shell)
?
谢谢.
请考虑以下代码:
int main()
{
int i;
volatile int* p = &i;
int *v = p;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这给出了一个错误g++
:
$ g++ -o volatile volatile.cpp
volatile.cpp: In function ‘int main()’:
volatile.cpp:6: error: invalid conversion from ‘volatile int*’ to ‘int*’
Run Code Online (Sandbox Code Playgroud)
我的意图是我想要p
挥发性.但是,一旦我读过它的值p
,我就不在乎访问v
是不是易变的.为什么要求v
声明为volatile?
这当然是假设的代码.在实际情况下,你可以想像,p
指向一个内存位置,但在外部修改,我想v
指向该位置p
在时指出v = p
,即使后来p
被外部修改.因此p
是不稳定的,但v
事实并非如此.
顺便说一句,当我认为这是C和C++时,我对这种行为感兴趣,但在C中,这只会产生警告,而不是错误.
C++ 11 lambdas很棒!
但缺少一件事,就是如何安全地处理可变数据.
以下将在第一次计数后给出错误计数:
#include <cstdio>
#include <functional>
#include <memory>
std::function<int(void)> f1()
{
int k = 121;
return std::function<int(void)>([&]{return k++;});
}
int main()
{
int j = 50;
auto g = f1();
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
printf("%d\n", g());
}
Run Code Online (Sandbox Code Playgroud)
给,
$ g++-4.5 -std=c++0x -o test test.cpp && ./test
121
8365280
8365280
8365280
Run Code Online (Sandbox Code Playgroud)
原因是在f1()
返回后,k
超出范围但仍在堆栈上.所以第一次g()
执行k
是好的,但在那之后堆栈被破坏并k
失去其价值.
因此,我在C++ 11中设法安全地返回闭包的唯一方法是在堆上显式分配闭合变量:
std::function<int(void)> f2()
{
int k = 121;
std::shared_ptr<int> o = std::shared_ptr<int>(new int(k)); …
Run Code Online (Sandbox Code Playgroud) 我有一个获取数据的函数,并返回相同的数据或稍微修改过的版本.
我希望让我的程序做一件事,如果它改变了或另一件事,如果它没有改变.
以前我回来了一对(Bool,Object)
并用fst
它来检查它是否改变了.最近,我想到我可以通过返回对象并使用检查相等来简化代码==
.
但后来我意识到Haskell没有区分深度相等检查和"对象身份"(即指针相等).那么我怎么知道使用是否==
有效?我是否应该出于效率原因而避免使用它,或者是否存在依赖于编译器确定它不需要进行深度相等检查的情况?
通常我在编写初始程序时不会太担心效率,但这会影响我的模块的接口,所以我想在编写太多代码之前做到正确,并且似乎不值得让程序更多仅仅是一小段代码效率较低.此外,我想更好地了解我可以依靠GHC进行哪种优化来帮助我.
我想验证我的理解是否正确.这种事情很棘手,所以我几乎可以肯定我错过了什么.我有一个由实时线程和非实时线程组成的程序.我希望非RT线程能够将指针交换到RT线程使用的内存.
从文档中,我的理解是,这可以通过以下方式实现g++
:
// global
Data *rt_data;
Data *swap_data(Data *new_data)
{
#ifdef __GNUC__
// Atomic pointer swap.
Data *old_d = __sync_lock_test_and_set(&rt_data, new_data);
#else
// Non-atomic, cross your fingers.
Data *old_d = rt_data;
rt_data = new_data;
#endif
return old_d;
}
Run Code Online (Sandbox Code Playgroud)
这是程序中唯一rt_data
被修改的地方(初始设置除外).当rt_data
在实时上下文中使用,它被复制到本地指针.对于old_d
以后,当确定未使用旧内存时,它将在非RT线程中释放.它是否正确?我需要volatile
在任何地方吗?我应该调用其他同步原语吗?
顺便说一下,我在C++中这样做,虽然我对C的答案是否不同感兴趣
提前谢谢.
对Haskell来说还是一个新手......
我想读取文件的内容,用它做一些可能涉及IO的东西(现在使用putStrLn),然后将新内容写入同一个文件.
我提出了:
doit :: String -> IO ()
doit file = do
contents <- withFile tagfile ReadMode $ \h -> hGetContents h
putStrLn contents
withFile tagfile WriteMode $ \h -> hPutStrLn h "new content"
Run Code Online (Sandbox Code Playgroud)
然而,由于懒惰,这不起作用.文件内容不会打印.我发现这篇文章很好地解释了它.
该解决方案提出了有包括putStrLn
内withFile
:
doit :: String -> IO ()
doit file = do
withFile tagfile ReadMode $ \h -> do
contents <- hGetContents h
putStrLn contents
withFile tagfile WriteMode $ \h -> hPutStrLn h "new content"
Run Code Online (Sandbox Code Playgroud)
这有效,但这不是我想要做的.我最终将替换的操作putStrLn
可能很长,我不想让文件保持打开状态.一般情况下,我只希望能够获取文件内容,然后在使用该内容之前将其关闭.
我想出的解决方案如下: …
make -k
我运行时Emacs默认使用该命令compile
.但是,我几乎从不认为make
在错误之后继续运行是有用的,所以我总是删除-k
标志.有没有办法改变我的默认值,.emacs
以便它只是make
?