容器使用 memcpy 优化的单元测试

Unit test that the container uses memcpy optimization

提问人:Voivoid 提问时间:5/7/2023 最后编辑:wohlstadVoivoid 更新时间:5/8/2023 访问量:100

问:

假设有一些自定义的类似容器,它在其复制构造函数中使用 memcpy 优化来 memcpy 简单可构造的对象,而不是调用多个复制构造函数。std::vector

如何对优化是否真正应用进行单元测试?

struct foo { /* some members */ };
static_assert(std::is_trivially_copyable_v<foo>);

my_vector<foo> v1{ /* some foo objects */ };

my_vector<foo> v2 = v1; // how do I test that single memcpy was called for all foo objects instead of multiple foo copy ctors? or how do I test that none copy ctors were called at all?
C++ 单元测试 优化 复制构造函数

评论

0赞 doug 5/7/2023
你不能。您只能测试他们是否符合 memcpy 的条件。编译器优化不是在 c++ 语言中确定的。向复制 ctor 添加任何内容将导致它不再是微不足道的可复制的。
0赞 nielsen 5/7/2023
这里有一个密切相关的问题:stackoverflow.com/questions/35557041/......
0赞 Voivoid 5/8/2023
我相信这不是编译器(或标准库)优化,而是自定义数据结构优化。我只是想尝试确保我的容器实际上正确使用优化

答:

0赞 fabian 5/7/2023 #1

可能有一些方法可以将标准库实现替换为保存有关任何复制的数据(例如,请参阅如何替换 C 标准库函数?),但一般来说,最简单的方法是在其中包含复制实现的附加模板参数中传递:memcpy

struct default_copier
{
    void memcpy(void* dest, void const* src, size_t size) const noexcept
    {
        std::memcpy(dest, src, size);
    }
};

template<class T, class Copier = default_copier>
class my_vector
{
    [[no_unique_address]] Copier m_copier;

    T m_values [10]{};
public:
    my_vector()
    {
    }

    void fill_first(T const* values, size_t size)
    {
        if constexpr (std::is_trivially_copyable_v<T>)
        {
            m_copier.memcpy(m_values, values, sizeof(T) * size);
        }
        else
        {
            std::copy_n(values, size, m_values);
        }
    }

    Copier& copier()
    {
        return m_copier;
    }

};

struct test_copier
{
    size_t m_memcpyUseCount{ 0 };

    void memcpy(void* dest, void const* src, size_t size)
    {
        std::memcpy(dest, src, size);
        ++m_memcpyUseCount;
    }
};

int main() {
    {
        my_vector<int, test_copier> vectorOfTriviallyCopyable;
        int buffer[2]{};
        vectorOfTriviallyCopyable.fill_first(buffer, std::size(buffer));
        assert(vectorOfTriviallyCopyable.copier().m_memcpyUseCount == 1);
    }

    {
        my_vector<std::string, test_copier> vectorOfNonTriviallyCopyable;
        std::string buffer[2]{};
        vectorOfNonTriviallyCopyable.fill_first(buffer, std::size(buffer));
        assert(vectorOfNonTriviallyCopyable.copier().m_memcpyUseCount == 0);
    }

    return 0;
}

评论

0赞 Paul Sanders 5/8/2023
我们什么时候停止信任编译器了?
1赞 Eljay 5/8/2023
@PaulSanders • 我信任编译器。我不相信键盘后面的猴子拿着枪。
1赞 Paul Sanders 5/8/2023
@Eljay 尤其是当我拿着枪😸的时候
0赞 Voivoid 5/8/2023 #2

看起来有一些方法可以检测没有复制结构:

如果一个自定义容器是类似 std 的(这意味着它可以通过分配器进行参数化),则可以使用模拟分配器来观察任何容器的元素复制构造是否是通过观察分配器的方法完成的。如果没有方法调用,您可以非常确定没有进行复制构造。constructconstruct