[英]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;
}
您可以使用以下方法简化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。
(我的烦恼之一是,许多人似乎认为RAII只是关于智能指针(特别是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位值。 这意味着,如果您尝试发送的文件对于邮件中的“大小”字段而言太大,那么您将发现“大小”字段已损坏。 这特别令人烦恼,因为无论大小字段中的大小,您都发送了整个文件。 这意味着在某些情况下,文件的内容可以解释为下一条消息的标题。
幸运的是(尽管我很意外),您使用tellg
, resize
和read
确实可以确保您不会发生内存不足异常而崩溃,而不是如果文件太大而无法放入缓冲区, -内存缓冲区。 如果文件大小大于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.