为何std::optional<T>离开作用域时会触发T的两次析构?
替换无父QObject裸指针:std::unique_ptr vs std::optional 析构疑问
背景需求
我需要替换一段处理无父QObject对象的裸指针逻辑,这类对象被当作可选对象使用,原有代码如下:
if(m_file) delete m_file; m_file = new QFile(...);
std::unique_ptr和std::optional看起来都符合替代需求,但测试时发现std::optional的输出存在疑似异常的行为——T的析构函数似乎被调用了两次,因此担心会引发资源释放问题,目前更倾向于使用std::unique_ptr。
测试代码及输出
测试代码
struct Loud { Loud(std::string name) : m_name{ name } { print("Creating"); } Loud(const Loud& other) : m_name{ other.m_name } { print("Copying"); } Loud(Loud&& other) : m_name{ other.m_name }{ print("Moving"); } ~Loud() { print("Destroying"); } Loud& operator=(const Loud& other){ this->m_name = other.m_name; print("Copy="); return *this;} Loud& operator=(Loud&& other){ this->m_name = other.m_name; print("Move="); return *this;} std::string m_name; void print(std::string operation) { std::cout << operation << " " << m_name << "\n"; } }; void optionalTest() { std::optional<Loud> opt; opt = Loud("opt 1"); opt = Loud("opt 2"); } void uniqueTest() { std::unique_ptr<Loud> unique; unique = std::make_unique<Loud>("unique 1"); unique = std::make_unique<Loud>("unique 2"); } int main() { optionalTest(); std::cout << "\n"; uniqueTest(); }
初始输出
Creating opt 1 Moving opt 1 Destroying opt 1 Creating opt 2 Move= opt 2 Destroying opt 2 Destroying opt 2 <-- 为何会这样? Creating unique 1 Creating unique 2 Destroying unique 1 Destroying unique 2
补充验证
后来修改了移动赋值运算符,在移动操作后修改other.m_name以标记被移动的对象,输出结果清晰显示:只有最后一次析构是std::optional<Loud>对象自身销毁,其余析构均来自临时对象。
修改后的移动赋值运算符
Loud& operator=(Loud&& other){ this->m_name = other.m_name; other.m_name += " (mvd from)"; print("Move="); return *this; }
修改后输出
Creating opt 1 Moving opt 1 Destroying opt 1 (mvd from) Creating opt 2 Move= opt 2 Destroying opt 2 (mvd from) Destroying opt 2
内容的提问来源于stack exchange,提问作者Jens Joberg
相关产品推荐
相关产品推荐

