复制构造函数const char *和Shared_ptr

时间:2013-07-30 11:26:11

标签: c++ constructor shared-ptr

我有一个班级Keywords

#include <boost/lambda/lambda.hpp>
class Keywords
{
    public:
        ///Constructor
        Keywords(const char*,vector<shared_ptr<RegularExpression>>,vector<string>);
        Keywords(const Keywords& other);
    private:
        const char * xmlFile;
        vector<shared_ptr<RegularExpression>> vreg;
        vector<string> sw;
}

我想为const char*vector<shared_ptr<RegularExpression>>

构建一个副本构造函数

我是否正确编码?

Keywords::Keywords(const Keywords& other):xmlFile(new char[100]),vreg(other.vreg.size())
{
    strcpy((char*)xmlFile, (char*)other.xmlFile);
    for (std::size_t i = 0; i < other.vreg.size(); ++i)
        vreg[i] = shared_ptr<RegularExpression>(new RegularExpression(*other.vreg[i]));
}

从我理解的内容我制作副本Const char *和shared_ptr的向量。

谢谢。

* 所以删除const char后我会有*

class Keywords
{
    public:
        ///Constructor
        Keywords(string,vector<shared_ptr<RegularExpression>>,vector<string>);
        Keywords(const Keywords& other);
    private:
        string xmlFile;
        vector<shared_ptr<RegularExpression>> vreg;
        vector<string> sw;
}

,复制构造函数为:

Keywords::Keywords(const Keywords& other):vreg(other.vreg.size()),sw(other.sw)
{
    for (std::size_t i = 0; i < other.vreg.size(); ++i)
        vreg[i] = shared_ptr<RegularExpression>(new RegularExpression(*other.vreg[i]));
}

Destcrutor:

Keywords::~Keywords()
{
    sw.clear();
    vreg.erase(vreg.begin());
}

1 个答案:

答案 0 :(得分:0)

这里有两种选择。您可能想要使用的是编译器提供的默认复制构造函数:

class Keywords {
    std::string xmlFile;
    std::vector<std::shared_ptr<RegularExpression>> vreg;
    std::vector<std::string> sw;

public:
    Keywords(const char *xmlFile,
             const std::vector<std::shared_ptr<RegularExpression>>& vreg,
             const std::vector<std::string>& sw)
      : xmlFile(xmlFile), vreg(vreg), sw(sw) {}

    // Look, Ma, no special member functions!
};

在此上下文中,默认的复制构造函数将完全按照您(最有可能)的要求执行:它将复制vreg向量,这意味着复制 shared_ptr 元素向量 - 但不是深度复制 RegularExpression 对象本身!你(很可能)不想深层复制这些对象,因为复制它们的成本很高,我猜它使用原件就像使用副本一样合适。通常你不得不担心内存管理 - 现在两个不同的Keywords对象声称拥有它们,它的工作是释放原件吗? - 但在这种情况下100%解决了,因为两个Keywords对象将共享所有权。那是shared_ptr 做的

这是一个很好的例子,被称为零度规则。熟悉的三条规则(或五条,或六条规则)表示如果定义一个特殊的成员函数,则应该全部定义它们。零规则说你不应该定义任何特殊成员函数,除非你做的事情非常棘手。


如果希望在这里变得棘手,并编写一个自定义复制构造函数 执行RegularExpression元素的深层复制,

......好吧,你应该问问自己为什么你不只是首先使用std::vector<RegularExpression> vreg - 那么你仍然可以使用Zero of Rule,因为默认的拷贝构造函数会变深就像你显然想要的那样为你复制。

但是如果你想要做狡猾的事情,那么你是不可动摇的,你就这样做:

class Keywords {
    std::string xmlFile;
    std::vector<std::shared_ptr<RegularExpression>> vreg;
    std::vector<std::string> sw;

public:
    Keywords(const char *xmlFile,
             const std::vector<std::shared_ptr<RegularExpression>>& vreg,
             const std::vector<std::string>& sw)
      : xmlFile(xmlFile), vreg(vreg), sw(sw) {}

    Keywords(const Keywords& rhs)
      : xmlFile(rhs.xmlFile), sw(rhs.sw)
    {
        vreg.reserve(rhs.vreg.size());
        for (auto&& sptr : rhs.vreg) {
            vreg.emplace_back(std::make_shared<RegularExpression>(*sptr));
        }
    }

    // Don't forget to implement copy-assignment too!
    // I'm just going to delete it here to keep anyone from using it.
    //
    Keywords& operator= (const Keywords&) = delete;
};

此实现可能无法执行您想要的操作;例如,如果在复制操作之前我们有rhs.vreg[0] == rhs.vreg[1],我们的构造函数将悄悄地制作该单个RegularExpression对象的两个副本,并为我们提供一个新的Keywords对象*this this->vreg[0] != this->vreg[1]。这仅仅是一般原则的具体应用,即很难制作任意指针图的副本。

您是否注意到这行代码有多长?

    vreg.emplace_back(std::make_shared<RegularExpression>(*sptr));

这是普通C ++ 11代码中的一个红旗。在普通代码中,我们不必编写像RegularExpression这样的显式类型;编译器只能推断出类型。如果我想复制sptr,我可以写vreg.emplace_back(sptr) - 没有明确的类型!但在这里我必须写出std::make_shared<RegularExpression>(...)。这很尴尬...... 因为我做错了 正常取{{1} ,取消引用它,复制构造指向 shared_ptr的东西,然后将其重新包装在具有不同所有权的新shared_ptr中。这是一个复杂而奇怪的操作,所以在C ++ 11中执行它的语法是复杂而奇怪的。

在这种情况下,我建议是棘手的。 :)