c++ lambda,无法访问拷贝捕获的变量

标签 c++ lambda

我有这个发送和接收 lambda 函数的简单客户端/服务器套接字代码。问题出在 recvlambda() 函数内部的客户端上,当我在接收到它后尝试调用 lambda 时,出现段错误 @

printf("Hello World! %i, %i\n", x, y);

调试显示x和y无法访问,它们的内存地址是错误的。

我在 Ubuntu 13.10 上使用 gcc 4.8.1。

我正在将 x、y 复制到 sendlambda() 函数中的 lambda。这不应该是段错误。知道为什么吗?

#include <iostream>
#include <time.h>
#include <gmpxx.h>

using namespace std;

typedef int (*func)();

/* Server code in C */

  #include <sys/types.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
#include <functional>

void sendlambda(int ConnectFD)
{
    int x = 2342342;
    int y = 23454234;
    function<int (void)> f = [x, y]() mutable -> int
    {
       printf("Hello World! %i, %i\n", x, y);
    };
    printf("sending lambda of %i bytes\n", sizeof(f));
    write(ConnectFD, (void*)&f, sizeof(f));
}


void recvlambda(int SocketFD)
{
    char buffer[1024];
    read(SocketFD, (void*)buffer, sizeof(buffer));
    function<int (void)> &f = *(function<int (void)>  *)buffer;
    f();
}

int server()
{
    printf("server\n");
    struct sockaddr_in stSockAddr;
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(-1 == SocketFD)
    {
        printf("can not create socket\n");
        exit(EXIT_FAILURE);
    }

    memset(&stSockAddr, 0, sizeof(stSockAddr));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(1100);
    stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
    {
        printf("error bind failed\n");
        close(SocketFD);
        exit(EXIT_FAILURE);
    }

    if(-1 == listen(SocketFD, 10))
    {
        printf("error listen failed\n");
        close(SocketFD);
        exit(EXIT_FAILURE);
    }

    for(;;)
    {
        int ConnectFD = accept(SocketFD, NULL, NULL);

        if(0 > ConnectFD)
        {
            printf("error accept failed\n");
            close(SocketFD);
            exit(EXIT_FAILURE);
        }

        /* perform read write operations ...*/
        sendlambda(ConnectFD);

        if (-1 == shutdown(ConnectFD, SHUT_RDWR))
        {
            printf("can not shutdown socket\n");
            close(ConnectFD);
            close(SocketFD);
            exit(EXIT_FAILURE);
        }
        close(ConnectFD);
    }

    close(SocketFD);
    return EXIT_SUCCESS;
}


int client()
{
    printf("client\n");
    struct sockaddr_in stSockAddr;
    int Res;
    int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (-1 == SocketFD)
    {
        printf("cannot create socket\n");
        exit(EXIT_FAILURE);
    }

    memset(&stSockAddr, 0, sizeof(stSockAddr));

    stSockAddr.sin_family = AF_INET;
    stSockAddr.sin_port = htons(1100);
    Res = inet_pton(AF_INET, "127.0.0.1", &stSockAddr.sin_addr);

    if (0 > Res)
    {
        printf("error: first parameter is not a valid address family\n");
        close(SocketFD);
        exit(EXIT_FAILURE);
    }
    else if (0 == Res)
    {
        printf("char string (second parameter does not contain valid ipaddress\n)");
        close(SocketFD);
        exit(EXIT_FAILURE);
    }

    if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr)))
    {
        printf("connect failed\n");
        close(SocketFD);
        exit(EXIT_FAILURE);
    }

    /* perform read write operations ... */
    recvlambda(SocketFD);

    (void) shutdown(SocketFD, SHUT_RDWR);

    close(SocketFD);
    return EXIT_SUCCESS;
}

int main(int argc, char** argv)
{
    if(argc>1 && strcmp(argv[1], "server")==0)
        server();
    else
        client();
    return 0;
}

最佳答案

一般来说,您不能指望按位复制复杂类型(如 std::function)会正常工作。

这是可能发生的情况:在服务器进程中创建的 std::function 对象持有一个函数指针,指向您用于初始化它的 lambda,它驻留在服务器进程的内存中。当客户端进程收到它时,它会尝试调用此函数指针,该指针指向不同进程的地址空间(服务器进程的地址空间)。这个段错误不足为奇。

但无论如何你都处于未定义的行为领域,因为你分配了一个字符数组,然后试图访问它,就好像它是一个 std::function 对象一样。

关于c++ lambda,无法访问拷贝捕获的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22054040/

相关文章:

c++ - 从 RAII 类的析构函数中抛出异常

c++ - 在没有互斥锁的情况下重新计数时如何避免竞争条件?

c# - 根据 ID 从列表中查找项目

c# - c# 与 vb.net 中的 lambda 表达式

java - Java 中函数式接口(interface)的威力在哪里?

lambda - (反射(reflection))隐式和显式 lambda 声明

c++ - 从工作线程更新 QtCharts 的正确方法?

c++ - IBM Rhapsody 中状态图终止连接器的理解

c++ - 使用 hashmaps c++ 查找最常用的词

C++11:如何通过继承使用 std::mem_fn 和 std::bind