簡體   English   中英

學習C ++向量...我這樣做正確嗎? 我對vector :: push_back()的反復調用可以簡化嗎?

[英]Learning C++ vectors… Am I doing this correctly? Can my repeated calls to vector::push_back() be simplified?

首先,我要說這個程序絕不是有用的。 這只是我寫的東西來測試和學習如何使用向量。

在此示例中,我正在采取一些我正在從事的現實生活項目中需要做的動作。 我不得不從Google上大約20個不同的例子中找出如何做很多事情。

這是我第一次對向量做任何事情, 我想確保自己所做的一切都是安全的 我還想知道是否可以簡化對vector::push_back()重復調用? 請注意,該代碼確實可以按照我的預期工作。 我只是想看看我是否忽略了任何東西,誤解了什么,撥打不安全的電話等。

最后一件事... 我也想學習如何使用智能指針( auto_ptr )。 但是到目前為止,我還沒有看到這個例子會受益嗎?

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;
typedef vector<unsigned char> message;


void append_file( message& buffer, int header_size )
{

    ifstream is("vector",ifstream::binary);
    is.seekg(0,ios::end);
    int length = is.tellg();
    is.seekg(0, ios::beg);

    buffer.reserve( header_size + length );
    buffer.resize( header_size +length );

    is.read( (char*)&buffer[header_size], length );
    is.close();

    buffer.at(4) = (buffer.size() & 0xFF00) >> 8;
    buffer.at(5) = buffer.size() & 0xFF;

}

int main( int argc, char *argv[] )
{

    while( true ) //this is just for me to watch memory usage
    {
        message msg;

        msg.push_back(0x00);
        msg.push_back(0x00);
        msg.push_back(0x01);
        msg.push_back(0x82);
        msg.push_back(0x00);
        msg.push_back(0x06);

        msg.push_back(0x01);
        msg.push_back(0x01);
        msg.push_back(0x20);
        msg.push_back(0x01);
        msg.push_back(0x25);
        msg.push_back(0x04);

        int header = msg.size();

        append_file( msg, header );

        ofstream os("test.dt",ofstream::binary);
        os.write( (char*)&msg[0], msg.size() );
        os.close();

        cout << "Wrote " << msg.size() << " bytes" << endl;

        cout << "Press any key to repeat...";
        cin.get();

    } //it is my understanding from my reading on vectors that the memory will be de-allocated here. Is this correct? It seems to be? At least on Linux.

    return 0;

}


注意:請不要提及boost,MFC或ATL。

您可以使用以下方法簡化msg初始化:

#include <algorithm>

message msg(10);
std::copy_n("\x00\x00\x01\x82\x00\x06\x01\x01\x20\x01\x25\x04", msg, 10);

我還想知道是否可以簡化對vector :: push_back()的重復調用?

不多。 在C ++ 11中,您可以使用元素列表( message msg = {0x00, 0x00, 0x01.....}初始化向量,但這需要編譯器支持此功能,並且您的編譯器很有可能尚不支持。

最后一件事...我也想學習如何使用智能指針(auto_ptr)。 但是到目前為止,我還沒有看到這個例子會受益嗎?

你是對的。 神奇的詞是RAII:資源獲取是初始化。 這意味着資源應歸C ++對象所有,這些對象負責獲取和釋放資源。 智能指針是執行此操作的一種方法(您有一個指向某些已分配堆的內存的指針,並將其包裝在一個智能指針中,該指針負責在時間到時釋放內存),但使用std::vector (或其他標准庫容器也實現RAII語義,它們擁有放置在其中的對象,並在需要釋放它們時負責釋放它們。

您自己的自建對象也可以這樣做。 在這方面,智能指針沒有什么特別的,它們只是RAII化原始指針的便捷捷徑。 但是,還有許多其他方法可以使您的資源使用RAII。

(我的煩惱之一是,許多人似乎認為RAI​​I只是關於智能指針(特別是shared_ptr ):如果要避免內存泄漏,則需要將所有內容都放在shared_ptr 。這是不正確的。重要的是,您的對象設計時具有清晰的所有權語義,以便始終清楚哪個對象擁有資源(資源可能是內存分配,文件句柄,窗口,網絡套接字或任何其他需要(被獲取和釋放),以便所有者負責釋放擁有的資源。智能指針只是行為類似的預制類。

關於auto_ptr ,請遠離它。 這不是很有用。 它不能安全地存儲在std容器中,並且具有一些古怪的行為,這就是為什么它在C ++ 11中已棄用。

而是使用“新一代”智能指針: shared_ptr (如果您要共享所有權), scoped_ptr (如果您希望將專有的,不可轉讓的所有權綁定到單個作用域)或unique_ptr ,其作用類似於auto_ptr但是作品

前兩個位於Boost(無論如何都應使用)和TR1(可能隨編譯器一起提供)中,而所有三個都在C ++ 11標准庫中。

另一種簡化方法:

message m;
std::back_insert_iterator<message> i(m);

i = 0x00;
i = 0x00;
i = 0x01;
i = 0x82;
i = 0x00;
i = 0x06;

i = 0x01;
i = 0x01;
i = 0x20;
i = 0x01;
i = 0x25;
i = 0x04;

這是初始化消息的更好方法:

static const char header[] = { '\x00', '\x00', '\x01', '\x82', '\x00',
                               '\x06', '\x01', '\x01', '\x20', '\x01',
                               '\x25', '\x04' };
vector<char> msg(header, header + (sizeof(header) / sizeof(header[0])));

當然,在C ++ 11中,您可以這樣做:

vector<char> msg { '\x00', '\x00', '\x01', '\x82', '\x00', '\x06',
                   '\x01', '\x01', '\x20', '\x01', '\x25', '\x04' };

至於其他地方提到的swap技巧...我認為這不是一個好主意。 除非您的緩沖區有時有絕對巨大的消息,然后返回到相對較小的消息,否則您損失的多於swap技巧帶來的收益。 您不希望底層的向量一直在分配內存,而與新的空向量交換會強制發生這種情況。

順便說一句,在重用向量時,構造函數調用可以替換為assign調用,如下所示:

 msg.assign(header, header + (sizeof(header) / sizeof(header[0]));

另外,您的代碼也有問題。 您不驗證文件大小是否適合16位值。 這意味着,如果您嘗試發送的文件對於郵件中的“大小”字段而言太大,那么您將發現“大小”字段已損壞。 這特別令人煩惱,因為無論大小字段中的大小,您都發送了整個文件。 這意味着在某些情況下,文件的內容可以解釋為下一條消息的標題。

幸運的是(盡管我很意外),您使用tellgresizeread確實可以確保您不會發生內存不足異常而崩潰,而不是如果文件太大而無法放入緩沖區, -內存緩沖區。 如果文件大小大於2G,則可能會出現負欠載情況。 如果發生這種情況,我不會冒險猜測會發生什么。 length可能不應該是整數。 找出應該為您提供什么類型的tellg ,然后改用它。

是的,它們可以與boost庫Assign( boost boost )附加功能一起使用,或者在C ++ 11中,它們也可以變得更聰明。

總體而言,您無需混合使用預留空間和調整大小。 您應該選擇最適合您的。 reserve()保證您可以分配許多項目而無需向量重新分配空間。 resize()表示內存已分配,您可以對其進行寫入。

還要記住,按照標准,永遠不需要向量來返回它分配的內存。 因此,舉例來說,如果向量增長到一百萬個元素,然后只需要十個元素,那么該向量將擁有系統內存以存儲百萬個元素。 這可以通過swap()技巧解決。

std::vector<int> foo(100000);

std::vector<int> small(10);

foo.swap(small); // now when small goes out of scope the 1,000,000 mem allocated
                 // vector shall be freed;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM