github_34833805 2025-03-04 14:56 采纳率: 36.4%
浏览 19

c++中静态变量为什么还能有两个实例地址

大前提:本人java,跟着ai去写c++
前提:一个仿真软件,用c++写的,我想通过增加一些代码实现操作仿真时对象的动作,比如:飞机开火,需求不是很复杂
思路:增加一个http服务,随软件启动启动,使用仿真软件本身监听方法拿到仿真对象,写到一个静态变量中,触发http服务,遍历一下静态变量,先实现这么多,通了再说其他
问题:往静态变量里写没有问题,可以看到数量有增加,但是http服务去读这个变量就是空的,打印内存地址是不同的,怎么静态变量还能有来两个,不知道怎么改了
代码:
就写了这么一个hpp文件

// global_vector.h
#ifndef HTTP_SERVER_HPP
#define HTTP_SERVER_HPP

#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <string>
#include <vector>

#include <qdebug.h>
#include "../tools/wkf/core/source/WkfPlatform.hpp"


#pragma comment(lib, "ws2_32.lib")

#define DEFAULT_PORT 8080
#define BUFFER_SIZE 1024
#define HEADINGDEGREES 5.00

class HttpServer {
private:
    WSADATA wsaData;
    SOCKET listenSocket;
    sockaddr_in serverAddr;
    int port;

    std::atomic<bool> running{ true };

    // 处理HTTP请求并生成响应
    std::string handleHttpRequest(const char* request) {
        std::string response = "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html\r\n"
            "Content-Length: 38\r\n"
            "\r\n"
            "<html><body><h1>Hello, World!</h1></body></html>";
        return response;
    }

    // 初始化Winsock库
    bool initWinsock() {
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
            std::cerr << "WSAStartup failed: " << WSAGetLastError() << std::endl;
            return false;
        }
        return true;
    }

    // 创建监听套接字
    bool createListenSocket() {
        listenSocket = socket(AF_INET, SOCK_STREAM, 0);
        if (listenSocket == INVALID_SOCKET) {
            std::cerr << "Socket creation failed: " << WSAGetLastError() << std::endl;
            WSACleanup();
            return false;
        }
        return true;
    }

    // 配置服务器地址并绑定
    bool bindSocket() {
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = INADDR_ANY;
        serverAddr.sin_port = htons(port);

        if (bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
            std::cerr << "Bind failed: " << WSAGetLastError() << std::endl;
            closesocket(listenSocket);
            WSACleanup();
            return false;
        }
        return true;
    }

    // 开始监听连接
    bool startListening() {
        if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) {
            std::cerr << "Listen failed: " << WSAGetLastError() << std::endl;
            closesocket(listenSocket);
            WSACleanup();
            return false;
        }
        std::cout << "Server is listening on port " << port << "..." << std::endl;
        return true;
    }

    // 处理客户端连接
    void handleClientConnections() {
        while (running) {
            sockaddr_in clientAddr;
            int clientAddrLen = sizeof(clientAddr);
            SOCKET clientSocket = accept(listenSocket, (sockaddr*)&clientAddr, &clientAddrLen);
            if (clientSocket == INVALID_SOCKET) {
                std::cerr << "Accept failed: " << WSAGetLastError() << std::endl;
                continue;
            }

            char buffer[BUFFER_SIZE] = { 0 };
            int bytesReceived = recv(clientSocket, buffer, BUFFER_SIZE, 0);
            if (bytesReceived > 0) {
                std::cout << "Received request: " << buffer << std::endl;
                std::string response = handleHttpRequest(buffer);
                send(clientSocket, response.c_str(), static_cast<int>(response.length()), 0);    
            }
            printGlobalVector2();
            closesocket(clientSocket);
        }
    }
    

public:
    static std::vector<wkf::Platform*> m_platForm;

    HttpServer(int port = DEFAULT_PORT) : port(port)
    {
        //m_platForm.clear(); 
    }

    ~HttpServer() 
    {
        //m_platForm.clear();
        if (running)
        {
            stop();
        }
        
    }
    // 启动服务器
    void start() {
        if (!initWinsock()) return;
        if (!createListenSocket()) return;
        if (!bindSocket()) return;
        if (!startListening()) return;
        handleClientConnections();
    }

    // 停止服务器
    void stop() {
        running = false;
        closesocket(listenSocket);
        WSACleanup();
    }


    ////////////////////////
    void addElementToGlobalVector2(wkf::Platform* element) 
    {
        if (element)
        {
            m_platForm.push_back(element);
        }
    }


    /////
    void printGlobalVector2() 
    {
        std::cout << "m_platForm size : " << m_platForm.size() << std::endl;
        std::cout << "m_platForm address : " << &m_platForm << std::endl;

        if (m_platForm.size())
        {
            for (auto element : m_platForm) {
                std::cout << "element GetName = " << std::endl;
                
            }
        }
    }

};


// 静态成员变量需要在类外初始化
std::vector<wkf::Platform*> HttpServer::m_platForm;
#endif

主方法内启动代码:

// 采用异步形式,要不会阻塞主方法
HttpServer server;
std::thread t(&HttpServer::start, &server);

写入的部分:

HttpServer server;
server.addElementToGlobalVector2(currentPlatformOfInterest);
// 这里打印是一直在增加的,我觉得是证明写入到了静态变量
server.printGlobalVector2();

内存地址不一样展示:

img


红色框是写入的打印,数量是一直可以增加的,内存地址也是一致的
黄色框就是在http线程内去读静态变量,是空,而且内存地址也不一样了

  • 写回答

4条回答 默认 最新

  • 精通代码大仙 2025-03-04 15:22
    关注

    感谢您提出了这个好问题!对一个问题良好的界定,已经将问题解决一半了!让【精通代码大仙】来帮您解答,本回答来自人工整理,并深度整合参考了付费大模型GPT4、Claude 3.5 Sonnet,以及最新的推理模型DeepSeek R1(DeepSeek-V3:AI 省钱与高效的奇迹,打破技术壁垒的东方魔法Deepseek为什么会这么爆火?DeepSeek大模型技术解析:从架构到应用的全面探索)的参考答案,如果还有疑问可以点击头像关注私信或评论(如果小黑屋了,无法评论,请私信)。 如果答案让您满意,请采纳、关注,您的采纳与关注是我最大的动力!非常感谢!

    从你的描述和代码来看,问题可能出在静态变量的初始化和线程安全上。以下是一些可能的原因和解决方案:
    
    ### 1. 静态变量的初始化
    在C++中,静态成员变量需要在类外进行初始化。你已经在`global_vector.h`文件中做了这一点:
    ```cpp
    std::vector<wkf::Platform*> HttpServer::m_platForm;
    

    但是,如果你在多个地方创建了HttpServer对象,并且这些对象是在不同的编译单元(即不同的源文件)中定义的,那么每个编译单元可能会有自己的静态变量实例。这会导致你在不同线程中看到不同的内存地址。

    2. 线程安全问题

    由于你在主线程和HTTP服务线程中都访问了同一个静态变量,因此需要确保对这个变量的操作是线程安全的。你可以使用互斥锁(mutex)来保护对静态变量的访问。

    解决方案

    1. 确保静态变量的唯一性

    确保静态变量只在一个地方被初始化,并且所有地方都引用同一个实例。可以在一个单独的源文件中进行初始化,例如global_vector.cpp

    // global_vector.cpp
    #include "global_vector.h"
    
    std::vector<wkf::Platform*> HttpServer::m_platForm;
    

    2. 使用互斥锁保证线程安全

    addElementToGlobalVector2printGlobalVector2方法中添加互斥锁,以确保线程安全:

    #include <mutex>
    
    class HttpServer {
    private:
        static std::mutex m_mutex;
    
    public:
        void addElementToGlobalVector2(wkf::Platform* element) 
        {
            if (element)
            {
                std::lock_guard<std::mutex> lock(m_mutex);
                m_platForm.push_back(element);
            }
        }
    
        void printGlobalVector2() 
        {
            std::lock_guard<std::mutex> lock(m_mutex);
            std::cout << "m_platForm size : " << m_platForm.size() << std::endl;
            std::cout << "m_platForm address : " << &m_platForm << std::endl;
    
            if (m_platForm.size())
            {
                for (auto element : m_platForm) {
                    std::cout << "element GetName = " << std::endl;
                }
            }
        }
    };
    
    std::mutex HttpServer::m_mutex;
    

    3. 检查对象实例

    确保你在主线程和HTTP服务线程中使用的HttpServer对象是同一个实例。如果在主线程中创建了一个HttpServer对象,在HTTP服务线程中又创建了一个新的HttpServer对象,那么它们会各自拥有独立的静态变量实例。

    总结

    • 确保静态变量只在一个地方被初始化。
    • 使用互斥锁保证对静态变量的访问是线程安全的。
    • 确保在主线程和HTTP服务线程中使用的HttpServer对象是同一个实例。

    通过以上步骤,你应该能够解决静态变量在不同线程中显示不同内存地址的问题。

    ```

    评论

报告相同问题?

问题事件

  • 修改了问题 3月4日
  • 创建了问题 3月4日