小编Ste*_*eve的帖子

C++ 11 lambda实现和内存模型

我想了解一些关于如何正确思考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)

c++ memory lambda c++11

88
推荐指数
2
解决办法
2万
查看次数

将Haskell程序分发为C源代码

假设我有一个Haskell程序或库,我想让非Haskeller,可能是C程序员可以访问.我可以使用GHC将其编译为C,然后将其作为C源分发吗?

如果可以,有人可以提供一个最小的例子吗?(例如,Makefile)

是否可以使用GHC自动确定所需的编译器标志和标头,然后将其捆绑到一个文件夹中?

基本上我有兴趣能够在C和Haskell中编写部分程序,然后将其作为tarball分发,但不要求目标安装GHC和Cabal.

haskell ghc

32
推荐指数
4
解决办法
1万
查看次数

gnuplot stdin,如何绘制两条线?

我正在尝试使用从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的每一列中获取不同图的数据?

谢谢.

gnuplot

26
推荐指数
3
解决办法
2万
查看次数

Makefile:过滤掉包含字符的字符串

我正在尝试过滤掉包含特定字符的字符串,但它不起作用.我想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)

谢谢.

makefile gnu-make

23
推荐指数
2
解决办法
2万
查看次数

为什么"易变"寄生在C++中?

请考虑以下代码:

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++ volatile

22
推荐指数
2
解决办法
4866
查看次数

在C++ 11 lambda语法中,堆分配闭包?

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)

c++ lambda c++11

21
推荐指数
1
解决办法
6922
查看次数

Haskell中的平等效率

我有一个获取数据的函数,并返回相同的数据或稍微修改过的版本.

我希望让我的程序做一件事,如果它改变了或另一件事,如果它没有改变.

以前我回来了一对(Bool,Object)并用fst它来检查它是否改变了.最近,我想到我可以通过返回对象并使用检查相等来简化代码==.

但后来我意识到Haskell没有区分深度相等检查和"对象身份"(即指针相等).那么我怎么知道使用是否==有效?我是否应该出于效率原因而避免使用它,或者是否存在依赖于编译器确定它不需要进行深度相等检查的情况?

通常我在编写初始程序时不会太担心效率,但这会影响我的模块的接口,所以我想在编写太多代码之前做到正确,并且似乎不值得让程序更多仅仅是一小段代码效率较低.此外,我想更好地了解我可以依靠GHC进行哪种优化来帮助我.

performance haskell

18
推荐指数
1
解决办法
920
查看次数

GNU C++中的原子交换

我想验证我的理解是否正确.这种事情很棘手,所以我几乎可以肯定我错过了什么.我有一个由实时线程和非实时线程组成的程序.我希望非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的答案是否不同感兴趣

提前谢谢.

c++ g++ atomic atomic-swap

18
推荐指数
1
解决办法
1万
查看次数

在Haskell中,我想读取一个文件然后写入它.我需要严格注释吗?

对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)

然而,由于懒惰,这不起作用.文件内容不会打印.我发现这篇文章很好地解释了它.

该解决方案提出了有包括putStrLnwithFile:

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可能很长,我不想让文件保持打开状态.一般情况下,我只希望能够获取文件内容,然后在使用该内容之前将其关闭.

我想出的解决方案如下: …

io file-io haskell lazy-evaluation

16
推荐指数
2
解决办法
6564
查看次数

我可以更改emacs的默认编译命令吗?

make -k我运行时Emacs默认使用该命令compile.但是,我几乎从不认为make在错误之后继续运行是有用的,所以我总是删除-k标志.有没有办法改变我的默认值,.emacs以便它只是make

emacs dot-emacs

14
推荐指数
2
解决办法
5133
查看次数