有一个类的std :: vector作为属性同一个类是一个很好的设计选择吗?

时间:2012-02-28 22:16:11

标签: c++ nested-class stdvector

我的问题陈述如下。存在“域”的概念,其由许多“子域”组成。现在,这些子域本身就是域名。以下是我可以做的事情的基本方法。我可以使用auto_ptr或其他东西,但现在暂时离开。

class Domain
{
private:
    Domain* subdomains;
}

然而,我能够编译并运行以下程序,我认为它做了同样的事情并给了我想要的东西。

#include <iostream>
#include <vector>
#include <string>

class Domain
{
private:
    std::string name_;
public:
    std::vector<Domain> subdomains;
    Domain(std::string name) : name_(name) {};
    std::string name() {return name_;}
    void addSubDomain(std::string subDomainName);
};

void Domain::addSubDomain(std::string subDomainName)
{
    subdomain.push_back(Domain(subDomainName));
}

int main()
{
    std::cout<<"Hello, World"<<std::endl;
    Domain domain("wow");
    domain.addSubDomain("wow-child");
    std::cout<<"Domain name is "<<domain.name()<<std::endl;
    std::cout<<"Subdomain name is "<<domain.subdomain[0].name()<<std::endl;
    return 0;
}

我运行它的输出是

$./main 
Hello, World
Domain name is wow
Subdomain name is wow-child

我的问题是,在实施以下内容时,我是否有任何陷阱?现在,我看不到任何东西。如果没有陷阱,那么这对我的问题来说是一个非常好的解决方案。

修改

如果这不是一个解决方案,那么我可以使用另一个不涉及原始指针管理的解决方案吗?

3 个答案:

答案 0 :(得分:6)

这是未定义的行为,因为在您定义成员时,该类尚未完全定义。此时,std::vector<Domain>需要实例化,从模板std::vector<T>到类std::vector<Domain>(以确定其大小等)。当实例化发生时,标准要求完全定义类。

答案 1 :(得分:2)

正如约翰内斯正确指出的那样,你的程序是未定义的。但是,如果这样做,你的程序将完全有效:

class Domain {
    …
    std::vector<Domain*> subdomains;
    …
};

当然,你必须管理指针。 (例外安全,RAII,三规则等等)。

答案 2 :(得分:0)

从stackoverflow中读取其他答案和许多其他问题后。我想用自己的话总结答案。尽管约翰内斯已正确回答了这个问题,但我还想补充一点。所以,就是这样。

  1. 由于Johannes的回答所给出的理由,在所有类型的用法中,问题中给出的代码的行为在C ++ 03中是未定义的。但是,在C ++ 11标准中,要求已经改变。除非该类特别允许,否则行为仍未定义。

    C ++ 11 $ 17.6.4.8其他函数(...)2。在下列情况下效果未定义:( ...)特别是 - 如果使用不完整类型(3.9)作为模板参数实例化模板组件,除非特别允许该组件。

  2. 当前的例子是有效的,因为std :: vector的特定实现不包含T类型的任何属性,只包含T *类型的属性。因此,这是一个幸运编译的案例,根据容器的不同,可能会或可能不会一直有效。

  3. 问题的解决方案是当前使用Boost :: Containers specifically support the incomplete types

  4. 如果需要,std :: unique_ptr和std :: shared_ptr指针可用作管理原始指针模型的替代品,只需很少捕获。这个问题的答案是here。人们可以看到详细的解释here。因此,如果需要一个std :: container,那么他可以使用上面的指针使用指针容器。但是,必须满足一些条件。这些条件在上面给出的链接中描述。

  5. 总而言之,现在最好的方法是使用boost :: containers。但是,他们引入了对boost的依赖。如果你想避免依赖,那么你可以使用std :: unique_ptr和std :: shared_ptr。但是,在可以做什么方面存在一些条件和限制。

    boost :: shared_ptr也允许使用不完整的类型。但是,这也有一些局限性。