在处理大量数据(GB)时,我使用数据数组的索引。由于对数据的访问可能会导致缓存效率低下,所以我想将数组中的一些数据和索引一起缓存,这样可以显著加快通过索引的操作。
缓存数据的数量是编译时的选择,应该包括零数量的缓存数据。我有大量的索引,所以在这种情况下,我不想为额外的空元素付费,比如
std::array
例如。
所以,我专门制作了一个模板:
using index_t = unsigned int;
using lexem_t = unsigned int;
template <std::size_t t_arg_cache_line_size>
struct lexem_index_with_cache_t {
index_t index;
std::array<lexem_t, t_arg_cache_line_size> cache_line;
constexpr std::size_t cache_line_size() const {
return t_arg_cache_line_size;
}
};
template<>
struct lexem_index_with_cache_t<0> {
index_t index;
static std::array<lexem_t, 0> cache_line;
constexpr std::size_t cache_line_size() const {
return 0;
}
};
std::array<lexem_t, 0> lexem_index_with_cache_t<0>::cache_line;
问题是我在零大小的专业化中使用的这个破解,它利用静态成员对
cache_line
而它是空的,并且并不真正需要访问。这使我可以避免在使用此模板的函数中进行专业化,例如:
using lexem_index_with_cache = lexem_index_with_cache_t<0>;
template <typename T>
class seq_forward_comparator_cached
{
const std::vector<T>& vec;
public:
seq_forward_comparator_cached(const std::vector<T>& vec) : vec(vec) { }
bool operator() (const lexem_index_with_cache& idx1, const lexem_index_with_cache& idx2)
{
if (idx1.index == idx2.index) {
return false;
}
const auto it1_cache_line = idx1.cache_line; // This code wouldnât compile in absence of static âhackâ
const auto it2_cache_line = idx2.cache_line; // This code wouldnât compile in absence of static âhackâ
auto res = std::lexicographical_compare_three_way(
it1_cache_line.begin(), it1_cache_line.end(),
it2_cache_line.begin(), it2_cache_line.end());
if (res == std::strong_ordering::equal) {
auto range1 = std::ranges::subrange(vec.begin() + idx1.index + idx1.cache_line_size(), vec.end());
auto range2 = std::ranges::subrange(vec.begin() + idx2.index + idx2.cache_line_size(), vec.end());
return std::ranges::lexicographical_compare(range1, range2);
}
return res == std::strong_ordering::less;
}
};
当然,我可以为零大小缓存实现这个模板的另一个模板专用化,但这会导致代码重复,而且我有很多这样的功能,所以我不想全部专用化。
在现代C++中,避免这种情况的正确方法是什么
static
另一方面,黑客攻击和可能的代码复制?
我不确定,也许根据类型包括一些条件代码会有所帮助。
我想避免包装访问
cache_line
到一个函数,但如果这是唯一的情况,请提供有关方法的线索。
可编译代码为
here
.