【发布时间】:2017-06-17 06:27:17
【问题描述】:
这里有一个小代码示例:
struct Data {
};
struct Init {
Data *m_data;
Init() : m_data(new Data) { }
~Init() {
delete m_data;
}
};
class Object {
private:
int m_initType;
Data *m_data;
public:
Object(const Init &init) : m_initType(0), m_data(init.m_data) { }
Object(Init &&init) : m_initType(1), m_data(init.m_data) { init.m_data = nullptr; }
~Object() {
if (m_initType==1) {
delete m_data;
}
}
};
对象可以通过两种方式初始化:
- const Init &:这个初始化只是将 m_data 存储为一个指针,m_data 不是拥有的,所以 ~Object() 不需要做任何事情(在这种情况下,m_data将在 ~Init()) 被销毁
- Init &&:这个初始化转移了m_data的所有权,Object成为m_data的所有者,所以~Object()需要销毁它
现在,有一个函数:
void somefunction(Object object);
这个函数在callInitA和callInitB中被调用:
void callInitA() {
Init x;
somefunction(x); // calls the "const Init &" constructor
}
void callInitB() {
somefunction(Init()); // calls the "Init &&" constructor
}
现在,这是我想要完成的事情:在 callInitA 的情况下,我想让编译器优化生成的临时 Object (Object 经常使用,我想减少代码大小)。
但是,编译器不会对其进行优化(使用 GCC 和 clang 进行测试)。
Object 被设计成它没有任何改变 m_initType 的函数,因此编译器将能够发现如果 m_initType 在构造时设置为 0,那么它不会改变,所以在析构函数中它仍然是 0 -> 根本不需要调用析构函数,因为它什么都不做。
甚至,m_initType 是 Object 的不必要成员:它只在销毁时才需要。
你有什么设计想法可以做到这一点吗?
更新:我的意思是使用某种 c++ 构造(帮助类等)。 C++ 是一门强大的语言,也许通过某种 c++ 技巧可以做到这一点。
(我最初的问题比这个简化的问题更复杂:对象可以用其他类型的初始化结构初始化,但所有对象的构造函数归结为以某种方式获取“数据*”)
【问题讨论】:
-
您已经分析并发现析构函数的存在是一个瓶颈?
-
为什么要手动管理内存?为什么不直接将
m_data设为std::unique_ptr,然后将析构函数设为= default;? -
你真的需要
Object(Init &&init),因为没有它,你也有正确的破坏。 -
The assembly 从您的代码生成表明 GCC 可以并且将避免执行
if (m_initType==1)检查,因为它可以证明它不需要这样做。这完全取决于编译器及其执行的优化。 -
这是库代码。此代码符合 >10000 个位置。所以实际上,如果不对其进行分析,我知道这个额外的代码会稍微减慢代码的速度。分析这种事情并不容易,如果不是不可能的话。如果我找到了解决这个问题的方法,那么我可以分析它:我获得了多少时间。