【发布时间】:2013-01-24 13:23:45
【问题描述】:
我花了一些时间寻找答案,但没有找到任何令人满意的答案。
只是对一些更有经验的 C++ 人如何解决这类问题感兴趣,因为现在我正在做的与生产相关的编码比原型设计要多。
假设你有一个类,它有一个 unordered_map (hashmap),它包含大量数据,比如 500Mb。您想编写一个访问器,以有效的方式返回该数据的某个子集。
采取以下方法,其中 BigData 是一些存储适量数据的类。
Class A
{
private:
unordered_map<string, BigData> m_map; // lots of data
public:
vector<BigData> get10BestItems()
{
vector<BigData> results;
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results;
}
};
访问器 get10BestItems 在此代码中效率不高,因为它首先将项目复制到结果向量,然后在函数返回时复制结果向量(从函数堆栈复制)。
由于各种原因,您不能在 c__ 中拥有引用向量,这将是显而易见的答案:
vector<BigData&> results; // vector can't contain references.
您可以在堆上创建结果向量并传递对它的引用:
vector<BigData>& get10BestItems() // returns a reference to the vector
{
vector<BigData> results = new vector<BigData>; // generate on heap
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results; // can return the reference
}
但是,如果您不小心,您将遇到内存泄漏问题。它也很慢(堆内存)并且仍然将数据从地图复制到向量。
所以我们可以回顾一下 c 风格的编码,只使用指针:
vector<BigData*> get10BestItems() // returns a vector of pointers
{
vector<BigData*> results ; // vectors of pointers
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results;
}
但大多数消息来源说除非绝对必要,否则不要使用指针。有使用 smart_pointers 和 boost ptr_vector 的选项,但我宁愿尽量避免这些。
我不认为地图将是静态的,所以我不太担心错误的指针。如果代码必须不同来处理指针,这只是一个问题。从风格上看,这并不令人愉快:
const BigData& getTheBestItem() // returns a const reference
{
string bestID;
for ( ........ // iterate over m_map, find bestID
// ...
return m_map[bestID] ; // return a referencr to the best item
}
vector<BigData*> get10BestItems() // returns a vector of pointers
{
vector<BigData*> results ; // vectors of pointers
for_each ........ // iterate over m_map and add 10 best items to results
// ...
return results;
};
例如,如果您想要单个项目,则返回引用很容易。
最后的选择是简单地将 Hash-map 公开并返回一个键向量(在本例中为字符串):
Class A
{
public:
unordered_map<string, BigData> m_map; // lots of data
vector<string> get10BestItemKeys()
{
vector<string> results;
for (........ // iterate over m_map and add 10 best KEYS to results
// ...
return results;
}
};
A aTest;
... // load data to map
vector <string> best10 = aTest.get10BestItemKeys();
for ( .... // iterate over all KEYs in best10
{
aTest.m_map.find(KEY); // do something with item.
// ...
}
什么是最好的解决方案?速度很重要,但我想要易于开发和安全的编程实践。
【问题讨论】:
-
“避免复制大数据” - 那么可能是对引用向量的引用?
-
这与您的问题没有直接关系,但正如您所说
get10BestItems()效率不高,我相信您可以将时间复杂度降低到 $O(K) + O(N \ log K)$ 和空间复杂度为 $O(K)$,其中 $N$ 是元素的数量,$K = 10$。您可以使用堆来保留 10 个最佳值,并使用比较函数在两个不同的值之间进行比较。你可以在这里看到我的意思的实现:github.com/lakshayg/collections/blob/master/algos/ksmallest.cpp
标签: c++ pointers vector reference accessor