清零STL容器使用的内存

13
我想使用STL容器(加上std::basic_string)暂时存储密钥或密码在内存中,并且在完成后我希望清零内存。
我最初打算使用参数化为自定义分配器的STL容器,在allocator::deallocate中清零内存,但我认为容器可以使用不来自指定分配器的内存。例如,一个std::vectorstd::string可能包含用于小型分配的固定大小数组成员,这似乎是合理的。
我是否有正当担忧?我应该(叹气)编写自己的容器吗?

对于 std::vector,你得跳过很多困难的步骤才能满足异常要求,并且仍然将数据存储在向量对象本身中。而对于 std::string,在对象中存储数据不仅是可能的,而且是相当常见的。 - Jerry Coffin
3
如果有人调用了std::vector::resizestd::vector::push_back,导致std::vector重新分配一个新的内存块并复制现有的缓冲区,会发生什么? - jamesdlin
我有什么遗漏吗?将清理工作交给存储对象而不是容器,这样做不更合理吗?因此,只需使容器存储一个类项,其析构函数会在自身清理后进行清理即可。当向量被调整大小时,不是会调用所有复制构造函数和析构函数吗...? - Roddy
哦 - 你是指例如键的向量,还是将键存储为字符向量?请记住,在std :: string中,实际字符存储在单独分配的内存块中,而std :: vector <std :: string> 基本上是指向字符的指针数组(加上长度信息等)。 - Roddy
@RoddyпјҡжҲ‘зҡ„ж„ҸжҖқжҳҜдҪҝз”Ёstd::vector<unsigned char>жқҘеӯҳеӮЁдәҢиҝӣеҲ¶еҜҶй’Ҙеқ—пјҢжҲ–иҖ…дҪҝз”Ёstd::vector<char>/std::stringжқҘеӯҳеӮЁеҜҶз ҒгҖӮеҰӮжһңжҲ‘дҪҝз”Ёзҡ„жҳҜйқһеҺҹе§Ӣзұ»еһӢзҡ„std::vectorпјҢжҲ‘иӮҜе®ҡдјҡеңЁvalue_typeзҡ„жһҗжһ„еҮҪж•°дёӯиҝӣиЎҢжё…йӣ¶ж“ҚдҪңгҖӮ - jamesdlin
显示剩余4条评论
3个回答

8
我会使用带有自定义分配器的std::vector来进行零值处理。根据May std::vector make use of small buffer optimization?中的答案,它不能使用小缓冲区优化,因此,使用自定义分配器,您应该是安全的。
如果您进一步使用该分配器来分配向量,然后使用智能指针来确保其正确释放(或手动释放),即使向量的内部内容(如大小)也将被清除。

2

您可以通过使用原始内存和定位new来分配字符串/向量,当您完成后,请调用析构函数、清零内存并释放原始内存。


百分之百真实且完全合理的方式!但是不可重用,而且有点绕过STL,转而使用核心C++运算符和内存技巧。你们所写的一切都可以通过编写自定义分配器来很好地包装,详见DateS的回答。 - quetzalcoatl
@quetzalcoatl:它正在使用STL,我指的是将字符串/向量对象放置在原始内存中。 - Daniel
不,你必须使用分配器。由vector/string分配的堆内存不会受到你清零对象内存的影响。即使你明确清零了vector中的值,仍然可能存在vector调整大小操作留下的副本。 - Eclipse
@Eclipse:我认为丹尼的意思是在使用自定义分配器时配合使用placement-new。 - jamesdlin
1
@quetzalcoatl:是的,如果您同时使用自定义分配器和放置 new,那么您可以确保覆盖了所有内存。 - Eclipse

-1
使用自定义字符串类,在其析构函数中将内存缓冲区清零。
class zeroed_string : public std::string
{
public:
    ~zeroed_string()
    {
        for (int i = 0; i < size(); ++i)
            (*this)[i] = 0;
    }
// ...
};

1
我认为std::string并不是作为基类使用的,否则它会有虚析构函数。顺便说一下,你的答案与下面的-4相同。 - BЈовић
1
正如我在另一个(现已删除的)答案中提到的那样,如果std::string需要重新分配内存块,则此方法将无法正常工作。其他评论也指出它不能与COW实现一起使用。 - jamesdlin
2
@BЈовић 如果你要使用多态,那么这是正确的,但在这种情况下你不需要。我认为人们对这一点过于担心了。 - Mark Ransom
2
@jamesdlin,我的回答是可能有效的最简单方法,但建议仍然是使用自定义字符串类来强制执行所需的安全性。如果std::string不可行,可以从头开始编写一个。 - Mark Ransom
2
这个被测试过吗?原则上,编译器可以将此循环优化掉,因为它(可能)没有可观察的行为。 - GManNickG
@GManNickG,我没有考虑过这一点。也许最好调用一个外部函数来清除内存,这样编译器就无法推断可能的副作用了。 - Mark Ransom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接