【问题标题】:how to copy constructor pointer vector c++如何复制构造函数指针向量c ++
【发布时间】:2019-04-17 18:12:33
【问题描述】:

我正在尝试为具有以下字段的“表”类创建一个复制构造函数:

private:
    int id ;
    int capacity;
    bool open;
    std::vector<Customer*> customersList;
    std::vector<OrderPair> orderList;

我想对所有字段进行深拷贝,并且我编写了以下代码,但我不确定是否对 customersList 进行了深拷贝,因为它是一个指针向量。有人能告诉我我是抄得深还是浅?提前谢谢你。

代码:

Table(const Table& t): capacity(t.getCapacity()), open(t.isOpen()), id(t.getId()){
    std::vector<Customer*> tmp(t.customersList);
    customersList = tmp;
}

或者也许我过度复制了,我应该只这样做? :

Table(const Table& t): customersList(t.customersList), capacity(t.getCapacity()), 
open(t.isOpen()), id(t.getId()){}

再次感谢!

【问题讨论】:

  • 如果您必须使用std::vectors 共享“有效负载”的对象,我强烈建议使用std::shared_ptr 而不是原始指针。这将使您的生活(尤其是共享实例)更轻松。复制 std::vector 将复制其元素 - 在您的情况下为原始指针。如果您没有在代码中明确执行此操作,它不会复制指针(指向的对象)。

标签: c++ c++11 pointers vector copy-constructor


【解决方案1】:

谁能告诉我我是抄得深还是浅?

你做了这两个/一个......取决于你正在考虑的间接级别。

std::vector 的复制构造函数做了一个深拷贝。即:原始对象中的向量customersList和构造对象中的向量customersList引用不同的内部缓冲区。如果你添加一个指向一个的指针,它不会自动反映在另一个向量中。

但是,向量内的元素是指针。指针具有相同的值,并指向相同的Customer 对象,并且没有复制任何Customer 对象。因此,副本很浅。


您显示的两个建议都有相同的结果,但后者更好,因为它只对向量执行一次操作(复制构造)而不是三项操作(成员的默认构造、本地的复制构造、成员的复制分配)。如果功能正确,实现相同功能的更简单方法是使用隐式生成的复制构造函数:Table(const Table&amp; t) = default; 它的作用相同,只是直接访问成员,而不是通过成员函数。

但实际上,您需要深入考虑要复制的内容。您需要Customer 对象的副本吗?然后,您确实需要一个自定义复制构造函数来复制初始化那些 Customer 对象。如果你这样做了,那么你可能应该使用智能指针向量而不是裸指针(假设你根本需要指针)。


我想创建另一个包含新指针的向量 - 一个新的内存分配,但具有相同的数据。换句话说,我想将数据复制到新的内存中,并将新的指针保存在customersList字段中。

在这种情况下,您的复制构造函数不会执行您想要的操作。您有新的指针,它没有新的值,也没有为客户对象分配内存(尽管有为向量分配的内存)。

我该怎么做?

您可以编写一个循环来遍历要复制的向量。在循环中,您可以分配新的客户对象,并使用向量指向的对象复制初始化它们。然后将新分配的指针插入到正在构造的成员向量中。

请注意,在这种情况下,指针将被拥有。你永远不应该拥有裸指针。重新迭代:在这种情况下,您应该使用智能指针(假设您根本需要指针)。

【讨论】:

  • 我想创建另一个包含新指针的向量 - 一个新的内存分配,但具有相同的数据。换句话说,我想将数据复制到新内存中,并将新指针保存在 customersList 字段中。我该怎么做?
  • 这是学校作业的一部分,我可以更改函数的签名(包括复制构造函数和字段),因此我无法创建智能或共享指针。
  • 感谢您的宝贵时间!
【解决方案2】:

您是否需要 C++98/03 中的非多态答案。它可以处理您的 customersList 中的一些指针可能不再指向任何地方。

Table(Table const &t) : id(t.id), capacity(t.capacity), open(t.open), orderList(t.orderList) {
    customersList.reserve(t.customersList.size());
    std::vector<Customer *>::const_iterator b = t.customersList.begin();
    std::vector<Customer *>::const_iterator const e = t.customersList.end();
    for (; b != e; ++b) {
        if (*b) {
            customersList.push_back(new Customer(**b));
        } else {
            customersList.resize(customersList.size() + 1);
        }
    }
}

【讨论】:

    【解决方案3】:

    std::vector&lt;Customer*&gt; 表示它不拥有Customer 对象,仅指存在于其他地方的对象。在这种情况下,您可以使用编译器生成的复制构造函数,为您执行成员(浅)复制。例如:

    Table(const Table& t) = default;
    

    【讨论】:

    • OP 从字面上说他们需要一个深拷贝,所以没有
    • 好吧,如果您回答的问题与提出的问题截然相反,因为“OP 不知道”,那么您可能在错误的网站上。
    • @LightnessRacesinOrbit 您对我的回答的解释不正确。重读我的第一句话。
    • 我没有误解你的答案,这是自洽的。然而,其陈述的前提与问题的前提相矛盾。此外,应该拥有一个指针向量并不罕见,尤其是在新人代码中(在生产过程中,我当然会教智能指针,因此所有权是明确的),特别是当问题的散文中特别要求深层复制时.
    【解决方案4】:

    不,你没有复制那些向量元素所指向的东西。如果我猜对了您的要求,您需要继续“手动”执行此操作:

    Table(const Table& t): capacity(t.getCapacity()), open(t.isOpen()), id(t.getId()){
        customersList.reserve(t.customersList.size());
        for (const auto old : t.customersList)
           customersList.push_back(new Customer(*old));
    }
    

    如果Customer 是继承层次结构的基础,则每个派生类中都需要一个virtual Customer* clone() 成员函数来执行正确的new,以避免切片。如果不是,为什么要存储指针?而是存储值并为自己省去这整个麻烦。

    顺便说一句,我希望您正确管理这些指针的生命周期,包括delete。总的来说,如果您使用某种智能指针而不是 Customer*,通常会更好。

    【讨论】:

    • 问题中没有关于谁拥有Customer 对象以及如何分配它们的信息。这段代码也不会编译。
    • 客户和表是分开的类,不是继承的。
    • @DekelShevach Customer 变成 Table 会非常令人惊讶,反之亦然。
    • @LightnessRacesinOrbit 然后我会创建一个新客户。谢谢!
    • @MaximEgorushkin 不要使用删除投票来表达分歧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多