离开默认构造函数后,unique_ptr变为空

时间:2015-01-23 16:17:49

标签: c++ smart-pointers pimpl-idiom

这是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删除包含的对象)。

2 个答案:

答案 0 :(得分:4)

C ++ 11中构造函数委派的正确语法是

TestClass01::TestClass01(int num) : TestClass01() // <-- here, in the ctor
{                                                 //     init list.
  pimpl->myint = num;
}

VS 2013支持,所以这应该适合你。您现在的方式只是创建一个无名的临时TestClass01对象,该对象会立即被销毁,并且根本不会影响当前的*this

答案 1 :(得分:2)

您无法直接调用构造函数。当你尝试时,你所做的只是创建一个在调用后消失的未命名临时,它根本不会影响当前对象。

以下是一些演示它的代码:

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观看演示。输出对象指针,注意它们是不同的。