c++ - 消除函数参数的复制

标签 c++ c++11 copy-elision

我正在编写一个自定义内存分配器。如果可能的话,我想制作这样的对象创建函数,以完全抽象创建过程。

template<typename T>
class CustomCreator
{
    virtual T& createObject(T value) __attribute__((always_inline))
    { 
        T* ptr = (T*)customAlloc();
        new (ptr) T(value);
        return *ptr;
    }
}

但这会导致复制。在这种情况下有没有办法强制消除复制?

这是我当前的测试代码。

#include <iostream>

struct AA
{
    inline static void test(AA aa) __attribute__((always_inline))
    {
        AA* ptr =   new AA(aa);
        delete ptr;
    }

    AA(AA const& aa)
    {
        printf("COPY!\n");
    }
    AA(int v)
    {
        printf("CTOR!\n");
    }
};

int main(int argc, const char * argv[])
{
    AA::test(AA(77));
    return 0;
}

我尝试将传递为T&T const&T&&T const&& ,但它仍然会复制。 我预计优化器会消除函数框架,因此函数参数可以推导为 R 值,但我仍然看到 COPY! 消息。

我也尝试过C++11转发模板,但我无法使用它,因为它不能是虚函数。

我的编译器是 Xcode 中包含的 Clang。 (clang-425.0.28) 优化级别设置为 -Os -flto

更新(供以后引用)

我编写了额外的测试,并使用 clang -Os -flto -S -emit-llvm -std=c++11 -stdlib=libc++ main.cpp; 选项检查生成的 LLVM IR。我观察到的是:(1)功能框架总是可以被消除的。 (2) 如果大对象(4096 字节)按值传递,则不会被消除。 (3) 使用 std::move 传递右值引用效果很好。 (4) 如果我不使用移动构造函数,编译器大多会回退到复制构造函数。

最佳答案

第一:
您期望优化器消除函数框架,但它不能,因为 (1) 该函数不是 RVO 欺骗并完全跳过复制构造函数的有效情况,并且 (2) 您的函数有副作用。即,将 copy 写入屏幕。因此优化器无法优化拷贝,因为代码表示必须将 copy 写入两次。我要做的就是删除 printf 调用,并检查程序集。最有可能的是,如果它很简单,它就会被优化掉。

第二:
如果成员复制构造函数可能有副作用(例如分配内存),那么很可能您是对的,它没有被优化掉。但是,您可以告诉它移动成员而不是复制它们,这可能正是您所期望的。为此,您需要确保您的类在复制构造函数旁边有一个移动构造函数。

inline static void test(AA aa) __attribute__((always_inline))
{
    AA* ptr =   new AA(std::move(aa));
    delete ptr;
}

第三:
事实上,即使这也不是您真正想要的。您可能想要的是更像完美转发的东西,它将直接将参数传递给构造函数而不复制任何内容。这意味着即使完全禁用优化器,您的代码仍然可以避免复制。 (请注意,这可能不适用于您的情况,模板不能像这样虚拟,除非它是专门的)

template<class ...types>
inline static void test(types&&... values) __attribute__((always_inline))
{
    AA* ptr =   new AA(std::forward<types>(values)...);
    delete ptr;
}

关于c++ - 消除函数参数的复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16430904/

相关文章:

c++ - find_if 与 lambda 和捕获变量

c++ - Visual C++ 2010 Beta 2 上的复制省略

c++ - 为什么下面的代码也会调用拷贝构造函数呢?

c++ - 用户定义复制构造函数时构造函数的行为

c++ - 有没有办法设置 printf 函数的输出序列?

c++ - 默认情况下是否创建 move 构造函数?

C++:如何在 UI 线程和 worker std::thread 之间使用 std::condition_variable

c++ - 不知道某些东西是否被省略会引入未定义的行为吗?

c++ - 让 static_visitor 在遍历 Boost 递归变体时修改它?

C++ 预处理器不知道模板参数?