unique_ptr 离开默认构造函数后变为空
unique_ptr becomes empty after leaving default constructor
这是 VS 2013 中的标准 pimpl:
.h:
#pragma once
#include<string>
#include<iostream>
#include <memory>
class TestClass01
{
private:
class impl;
std::unique_ptr<impl> pimpl;
public:
TestClass01();
TestClass01(int num, std::string str);
TestClass01(int num);
TestClass01(std::string str);
virtual ~TestClass01();
int ReturnMyInt();
std::string ReturnMyString();
};
.cpp
#include "stdafx.h"
#include "TestClass01.h"
#include <iostream>
class TestClass01::impl
{
public:
int myint;
std::string mystr;
};
TestClass01::TestClass01()
{
pimpl = std::make_unique<impl>();
}
TestClass01::TestClass01(int num, std::string str)
{
//pimpl = std::make_unique<impl>();
TestClass01();
pimpl->myint = num;
pimpl->mystr = str;
}
TestClass01::TestClass01(int num)
{
TestClass01();
pimpl->myint = num;
}
TestClass01::TestClass01(std::string str)
{
TestClass01();
pimpl->mystr = str;
}
TestClass01::~TestClass01()
{
std::cout << "Destroyed TestClass01 with int=" << pimpl->myint << " and str=" << pimpl->mystr;
}
int TestClass01::ReturnMyInt()
{
return pimpl->myint;
}
std::string TestClass01::ReturnMyString()
{
return pimpl->mystr;
}
此代码的问题在于,如果我从任何其他构造函数调用默认构造函数而不是直接实例化 impl,它会崩溃:
TestClass01::TestClass01(int num, std::string str)
{
//pimpl = std::make_unique<impl>(); -> This works, the line below doesn't
TestClass01();
pimpl->myint = num;
pimpl->mystr = str;
}
在TestClass01()下面一行; pimpl 是空的。但是在默认构造函数中设置断点会显示 pimpl 指向默认构造函数中的一个对象,只有在离开时才变为空。
是什么导致 pimpl 变空?它是一个成员变量,它不应该超出范围(因此导致 unique_ptr 删除包含的对象)。
您不能直接调用构造函数。当你尝试时,你所做的只是创建一个未命名的临时对象,它在调用后消失,它根本不会影响当前对象。
下面是一些演示代码:
struct test
{
test() { cout << "default constructor on " << this << endl; }
test(int) { cout << "int constructor on " << this << endl; test(); }
};
int main() {
test t(1);
cout << "test object at " << &t << endl;
return 0;
}
在 http://ideone.com/n2Thrn 查看演示。输出对象指针,注意它们是不同的。
C++11 中构造函数委托的正确语法是
TestClass01::TestClass01(int num) : TestClass01() // <-- here, in the ctor
{ // init list.
pimpl->myint = num;
}
VS 2013 支持,所以这应该适合你。你现在这样做的方式只是创建一个无名的临时 TestClass01
对象,它会立即被销毁并且根本不会影响当前的 *this
。
这是 VS 2013 中的标准 pimpl:
.h:
#pragma once
#include<string>
#include<iostream>
#include <memory>
class TestClass01
{
private:
class impl;
std::unique_ptr<impl> pimpl;
public:
TestClass01();
TestClass01(int num, std::string str);
TestClass01(int num);
TestClass01(std::string str);
virtual ~TestClass01();
int ReturnMyInt();
std::string ReturnMyString();
};
.cpp
#include "stdafx.h"
#include "TestClass01.h"
#include <iostream>
class TestClass01::impl
{
public:
int myint;
std::string mystr;
};
TestClass01::TestClass01()
{
pimpl = std::make_unique<impl>();
}
TestClass01::TestClass01(int num, std::string str)
{
//pimpl = std::make_unique<impl>();
TestClass01();
pimpl->myint = num;
pimpl->mystr = str;
}
TestClass01::TestClass01(int num)
{
TestClass01();
pimpl->myint = num;
}
TestClass01::TestClass01(std::string str)
{
TestClass01();
pimpl->mystr = str;
}
TestClass01::~TestClass01()
{
std::cout << "Destroyed TestClass01 with int=" << pimpl->myint << " and str=" << pimpl->mystr;
}
int TestClass01::ReturnMyInt()
{
return pimpl->myint;
}
std::string TestClass01::ReturnMyString()
{
return pimpl->mystr;
}
此代码的问题在于,如果我从任何其他构造函数调用默认构造函数而不是直接实例化 impl,它会崩溃:
TestClass01::TestClass01(int num, std::string str)
{
//pimpl = std::make_unique<impl>(); -> This works, the line below doesn't
TestClass01();
pimpl->myint = num;
pimpl->mystr = str;
}
在TestClass01()下面一行; pimpl 是空的。但是在默认构造函数中设置断点会显示 pimpl 指向默认构造函数中的一个对象,只有在离开时才变为空。
是什么导致 pimpl 变空?它是一个成员变量,它不应该超出范围(因此导致 unique_ptr 删除包含的对象)。
您不能直接调用构造函数。当你尝试时,你所做的只是创建一个未命名的临时对象,它在调用后消失,它根本不会影响当前对象。
下面是一些演示代码:
struct test
{
test() { cout << "default constructor on " << this << endl; }
test(int) { cout << "int constructor on " << this << endl; test(); }
};
int main() {
test t(1);
cout << "test object at " << &t << endl;
return 0;
}
在 http://ideone.com/n2Thrn 查看演示。输出对象指针,注意它们是不同的。
C++11 中构造函数委托的正确语法是
TestClass01::TestClass01(int num) : TestClass01() // <-- here, in the ctor
{ // init list.
pimpl->myint = num;
}
VS 2013 支持,所以这应该适合你。你现在这样做的方式只是创建一个无名的临时 TestClass01
对象,它会立即被销毁并且根本不会影响当前的 *this
。