首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >非指针类成员:它有多好?

非指针类成员:它有多好?
EN

Stack Overflow用户
提问于 2018-05-31 17:19:41
回答 2查看 500关注 0票数 6

我有一个需要在构造函数中初始化的非指针类成员:

代码语言:javascript
复制
class Alerter {

protected:
  Timer timer;

public:
  Alerter(int interval);
};

然后

代码语言:javascript
复制
Alerter::Alerter(int interval) {
    timer = createTimer(interval);
}

(简化代码只是为了演示问题)。

我有些怀疑和担心,timer可能首先是使用它的无参数构造函数创建的,然后该实例会被createTimer函数返回的内容覆盖。

这种方法有多好?可能的答案可能是:

  • 由其无参数构造函数创建的“空计时器”实际上并没有被创建,因为编译器足够智能,在改写该值之前会发现我们从未引用过它。
  • 空计时器会被创建,但这是可以的,因为编写得很好的代码应该支持一个廉价的无参数构造函数用于一次性使用,最好使用指针。

这些假设中哪一个(或者其他假设)是最正确的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-31 17:22:57

timer首先是默认构造的,然后分配。当然,您可以假设默认构造Timer或编译器优化的成本有多低,但在这里您不需要这样做,因为可以通过使用初始化器列表来防止默认构造:

代码语言:javascript
复制
Alerter::Alerter(int interval) : timer(createTimer(interval)) { }

这将会起作用,除非您的Timer类是可复制赋值的,但不是复制可构造的,这会很奇怪。

票数 11
EN

Stack Overflow用户

发布于 2018-05-31 17:33:16

两个构造函数都将被调用(然后赋值也会被调用)。

我已经扩展了你的例子:

代码语言:javascript
复制
class Timer
{
  public:
    Timer() : m_interval(0)
    {
        std::cout << "Constructor withOUT parameter has been called." << std::endl;
    }

    Timer(int interval) : m_interval(interval)
    {
        std::cout << "Constructor with parameter has been called." << std::endl;
    }

    Timer(const Timer& timer)
    {
        std::cout << "Copy constructor has been called." << std::endl;
        m_interval = timer.m_interval;
    }

    Timer(Timer&& timer)
    {
        std::cout << "Move constructor has been called." << std::endl;
        m_interval = timer.m_interval;
    }

    void operator=(Timer&& timer)
    {
        std::cout << "Move assignment has been called." << std::endl;
        m_interval = timer.m_interval;
    }

  private:
    int m_interval;
};

class Alerter
{
  protected:
    Timer timer;

  public:
    Alerter(int interval)
    {
        timer = Timer(interval);
    }
};

... 
Alerter alerter(12);
...

输出:

代码语言:javascript
复制
Constructor withOUT parameter has been called.
Constructor with parameter has been called.
Move assignment has been called.

回答你的问题。如果成员变量只初始化一次会更好,但这不是硬规则。例如,如果计时器是一个非常复杂的对象,但默认构造函数只创建了一个虚拟对象,那么它就不会太昂贵,也不会被接受。

所以,如果你能避免,最好还是避免。使用指针是一种可能的解决方案,但请注意以下几点:

  • 最好使用std::unique_ptr来避免内存泄漏。
  • 这肯定需要堆内存分配操作。如果对象无论如何都在堆上(例如使用复杂的内部结构,如STL容器),这不是问题。但是,如果对象非常简单,并且主要用例是将它们创建为本地对象,这可能会导致相当大的性能损失。这应该是一个有意识的设计决定。
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50620813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档