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