0

私はいくつかの char* ポインターを処理するプロジェクトで作業しており、std::string の代わりに char* を使用することがクラスの前提条件であるため...

私はこの構造定義とこのキューを持っています:

typedef struct packetQueue
{
    char* buf;
    int length;

    packetQueue()
    {
        buf = new char[];
        length = 0;
    }

    } PACKET;

concurrency::concurrent_queue IP_in_queue;

私はこのバッファを持っています:

char sendBuf[MSG_SIZE + sizeof (IP_PACKET_HEADER_T) + 1]; // String to be send

そして私の新しいバッファの構造:

PACKET ipQueue;

次に、これでバッファを埋めます:

// Concatenates the header with sended message
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));

memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);

ipQueue.buf = sendBuf;
ipQueue.length = packetSize;

そして、パケットをキュー IP_in_queue.push(ipQueue); にプッシュします。// IP_in_queue にバッファをプッシュします

念のため、これは私のループです:

while ( 1 )
{
    // Get the user input
    cout << "> ";
    cin.getline (buf, BUFLEN);

    IP_PACKET_HEADER_T sendHeader; // Store the header to be send
    PACKET ipQueue;

    char* fakeIPAddressDst, *readMessage; 

    delay = atoi(strtok (buf," ")); // Takes the first delay value
    fakeIPAddressDst = strtok (NULL, " "); // Stores the IP Address
    readMessage = strtok (NULL, " "); // Stores the sended message

    Sleep(delay); // Sleep the miliseconds defined

    // Fills the header with the data neccesary data
    sendHeader.DIP = inet_addr(fakeIPAddressDst);
    sendHeader.SIP = inet_addr(initAddress.fakeIpAddress);
    sendHeader.length = getStringLength(readMessage) + 1;
    packetSize = sizeof( sendHeader ) + sendHeader.length; // Defines the size of the packet to be send

    // Concatenates the header with sended message
    memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
    memcpy(&sendBuf[sizeof(sendHeader)], readMessage, sendHeader.length);

    ipQueue.buf = sendBuf;
    ipQueue.length = packetSize;

    numbytes = packetSize; // The number of bytes of sended buffer

    char sendedString[BUFLEN + 1]; // Variable for stores the data
    IP_PACKET_HEADER_T readHeader; // To store the header for showing the information

    // Print out the content of the packet
    // Copy from buf to the header
    memcpy( (void*)&readHeader, ipQueue.buf, sizeof( IP_PACKET_HEADER_T));
    // Copy message part
    memcpy( sendedString, &ipQueue.buf[sizeof(IP_PACKET_HEADER_T)], numbytes - sizeof(IP_PACKET_HEADER_T));
    // Append \0 to the end
    sendedString[numbytes - sizeof(IP_PACKET_HEADER_T)] = '\0';

    // Save the IP information of the packet in a struct for print on the screen
    struct in_addr fakeAddrHost;
    fakeAddrHost.s_addr = readHeader.SIP;

    // Print the neccesary data
    cout << "[IN] DST: " << fakeIPAddressDst << endl; // Fake IP address of the destination
    cout << "[IN] SRC: " << inet_ntoa(fakeAddrHost) << endl; // Fake IP address of the host
    cout << "[IN] MSG: " << sendedString << endl ; // Message to send

    IP_in_queue.push(ipQueue); // Push the buffer in the IP_in_queue
}

この手順でメモリ リークがあることはわかっていますが、よくわかりません。パケットをプッシュすると、buf ポインターが sendBuf を指し続けます。割り当てがそれを行うためですが、プログラムをプッシュした後に ipQueue 内のポインターを削除するとクラッシュします。その構造体をキューにプッシュした後、別のスレッドがその構造体をポップしようとします。明らかに、ipQueue ポインターを削除すると、バッファーが失われます。このメモリ リークを回避するにはどうすればよいでしょうか?

ありがとう

編集:

buf = nullptr の定義を使用したメモリ リーク

---------- Block 1 at 0x0068BB30: 264 bytes ----------
  Call Stack:
    d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (402): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::_Allocate_page + 0xF bytes
    f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (113): MSVCP110D.dll!Concurrency::details::_Micro_queue::_Push + 0xD bytes
    f:\dd\vctools\crt_bld\self_x86\crt\src\concurrent_queue.cpp (232): MSVCP110D.dll!Concurrency::details::_Concurrent_queue_base_v4::_Internal_push
    d:\program files (x86)\microsoft visual studio 11.0\vc\include\concurrent_queue.h (566): Host.exe!Concurrency::concurrent_queue<packetQueue,std::allocator<packetQueue> >::push + 0xF bytes
    d:\users\silex rpr\documents\visual studio 2012\projects\project2\project2\host.cpp (802): Host.exe!main
    f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (536): Host.exe!__tmainCRTStartup + 0x19 bytes
    f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (377): Host.exe!mainCRTStartup
    0x7662339A (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
    0x77179EF2 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
    0x77179EC5 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
4

3 に答える 3

1

最初に; これはCではありません。C++コンパイラを使用しています。Cの構造体は、メソッドとコンストラクターを持つことができず、存在newdeleteません。

次に、コンストラクターでメモリを割り当てますbufが、...

ipQueue.buf = sendBuf;

それはリークです。deleteへのすべての呼び出しを呼び出す必要がありますnew。で割り当てますbufnew、決して呼び出さないdeleteため、メモリがリークします。

ここに割り当てる理由はありませんbuf。nullに設定するだけです。

typedef struct packetQueue
{
    char* buf;
    int length;

    packetQueue()
        : buf(nullptr), length(0) { }
} PACKET;

ちなみに、これはCとC++の非常に厄介な組み合わせです。これはあなたの先生があなたたちに教えていることですか?

于 2012-09-23T22:30:51.493 に答える
0

メモリを割り当てるコンストラクタがあり、メモリを解放するデストラクタがないクラス(構造)があるため、メモリリークが発生します。

また、メンバーを公開してbuf割り当てます。したがって、クラスはメモリを解放するかどうかを制御できません。ただし、最初に割り当てる前に、コンストラクターで割り当てられたメモリを解放する必要がありますbuf

これを正しく行うには、bufフィールドをプライベートにし、デストラクタ、コピーコンストラクタ、および代入演算子(およびおそらくアクセサ関数)を追加する必要があります。ただし、それでも例外安全ではありません。

于 2012-09-23T22:31:23.903 に答える
0

あなたが抱えている問題は、コピーの構築とコピーの代入を見ていないことです。オブジェクトを にプッシュするstd::vector<T>と、オブジェクトがコピーされ、std::vector<T>代入を使用してオブジェクトが移動する可能性があります。デフォルトで生成されたコピー コンストラクターとコピー代入は、それぞれのメンバーをコピーまたは代入するだけです。つまり、いずれかのコピーを使用すると、2 つのオブジェクトが同じbuf. 破棄された最初のものは使用さdelete[] buf;れ、他のすべてのものは再び削除できない古いポインターを持ちます。つまり、次の 3 つのメソッドを に追加しますpacketQueue

struct packetQueue
{
    packetQueue(packetQueue const& other);             // copy constructor: copies the content
    packetQueue& operator= (packetQueue const& other); //copy assignment: updates the content
    ~packetQueue()                                     // destructor: release the memory
    void swap(packetQueue& other);                     // swap the content
    // other members
};

コピーの代入でコピーの構築と破棄を活用するには、swap()メンバーを用意すると便利です。これは簡単に実装でき、素晴らしくシンプルなコピーの代入を作成できるからです。

void packetQueue::swap(packetQueue& other) {
    std::swap(this->buf, other.buf);
    std::Swap(this->size, other.size);
}
packetQueue& packetQueue::operator= (packetQueue const& other) {
    packetQueue(other).swap(*this);
    return *this;
}
于 2012-09-23T22:38:50.293 に答える