【问题标题】:Why there is something wrong when invoking ctor in another ctor?为什么在另一个 ctor 中调用 ctor 时出现问题?
【发布时间】:2021-03-30 07:37:16
【问题描述】:

这是一个演示代码 sn-p(https://godbolt.org/z/31Tq3r):

 #include<iostream>

class Ctx
{
public:
    enum RUN_MOD
    {
        MOD_RT,
        MOD_NRT,
    };

    Ctx(RUN_MOD runType)
    {
        if(runType == MOD_RT)
        {
            Ctx();
        }
    }

    Ctx()
    {
        m_L = malloc(100);
        std::cout << "set m_L=" << m_L << std::endl;
    }

    void print()
    {
        std::cout <<"print() m_L=" << m_L << std::endl;
    }

private:
    void *m_L;

    const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
    const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
    const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};


int main()
{
    Ctx ctx(Ctx::RUN_MOD::MOD_RT);

    ctx.print();
}

以下是在 Ubuntu 上调用二进制程序时的输出:

set m_L=0x614c20 
print() m_L=0x400ad0

你看地址不一样。我确实通过调用Ctx::Ctx()(由Ctx::Ctx(RUN_MOD runType) 调用)来设置m_L。我真的很困惑。

【问题讨论】:

  • 我真的很困惑。 -- if(runType == MOD_RT) { Ctx();} -- 这不是你想的那样。
  • 我想重用一个特定的ctor。这段代码 sn-p 仅用于演示。
  • 您发布的代码是我们必须使用的,演示或不演示。那行代码不会“链接”下一个构造函数。
  • 不要在 C++ 中使用malloc。使用new。或者更好的是,使用std::unique_ptr。这样可以防止像现在这样的内存泄漏。
  • 在构造函数中调用构造函数没有错。它会完全按照你告诉它的去做。在您的情况下,您告诉它创建一个新的本地对象并立即销毁它。 (Aldo 导致即时内存泄漏)

标签: c++ c++11 constructor


【解决方案1】:

我找到了解决方案,这里是代码 sn-p(https://coliru.stacked-crooked.com/a/964309f60f62dbd4,它可以工作,但我还在努力理解它):

#include<iostream>

class Ctx
{
public:
    enum RUN_MOD
    {
        MOD_RT,
        MOD_NRT,
    };

    Ctx(RUN_MOD runType)
    {
        if(runType == MOD_RT)
        {
            new (this)Ctx();
        }
    }

    Ctx()
    {
        m_L = malloc(100);
        std::cout << "set m_L=" << m_L << std::endl;
    }

    void print()
    {
        std::cout <<"print() m_L=" << m_L << std::endl;
    }

    ~Ctx()
    {
        free(m_L);
    }

    Ctx(const Ctx&) = delete;  //to avoid double free

private:
    void *m_L;

    const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
    const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
    const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
};


int main()
{
    Ctx ctx(Ctx::RUN_MOD::MOD_RT);

    ctx.print();
}

【讨论】:

  • 抱歉,这个解决方案是 C++ 混淆的。
  • 所以现在你遇到了一个难题——你如何释放那个指针?你使用free,还是使用delete
  • 我使用free来释放分配的内存。请参阅编辑后的答案。
  • 我免费使用 -- 不好。 See this
【解决方案2】:

如果您正在寻找一个干净的解决方案,您可以使用一个函数,默认构造函数应该做什么。这样你就不需要构造函数委托,这 afaik 不能有条件地应用,你不必弄乱放置 new。

小例子:

class Ctx
{
private:
    void DefaultInit()
    {
        m_L = malloc(100);
        std::cout << "set m_L=" << m_L << std::endl;
    } 

public:
    Ctx(RUN_MOD runType)
    {
        if(runType == MOD_RT)
        {
            this->DefaultInit();
        }
    }

    Ctx()
    {
       this->DefaultInit();
    }
}

【讨论】:

    【解决方案3】:

    这个答案很好,但作者删除了它。 放在这里让更多人学习。

    他的代码:

    if(runType == MOD_RT)
    {
        Ctx();
    }
    

    创建一个临时的Ctx() 对象,然后——就是这样。不多也不少。一旦该行代码执行完毕,该临时文件就会被销毁。

    该类还有其他主要问题,例如使用malloc,由于不遵循3的规则,类泄漏内存,未初始化所有成员(我通过将m_L设置为nullptr来解决),等等

    【讨论】:

    • 我删除了它,因为@churill 给出的答案基本上是重复的。此外,您真的不应该逐字复制已删除的内容。其他人可以看到已删除的帖子。
    • 我明白了,我将删除重复的部分。但我认为您的回答更清楚地解释了代码的问题。您能否为我更详细地解释最后一段?(即“由于不遵循 3 规则,未初始化所有成员,类泄漏内存”。我可以稍后通过free 释放分配的内存。所以我我很困惑你为什么这么说。)
    • int main() { Ctx x1; Ctx x2 = x1; } -- 尝试一下,然后对“释放”的内容感到非常失望。你现在有一个双重释放错误。这就是rule of 3 的全部意义所在。转到该链接的管理资源部分。
    • @PaulMcKenzie 在仔细阅读上述部分后,我想我现在明白你的意思了。我应该为我的案例添加Ctx(const Ctx&amp;) = delete;m_L 指向的内存用作内存池)。我对吗?感谢您的慷慨帮助。
    【解决方案4】:

    构造函数委托只能在构造函数的member initialization list 内部使用,不能在构造函数的主体内部使用。 This answer 展示了如何完全避免使用构造函数委托,方法是创建一个通用初始化函数,然后多个构造函数可以根据需要调用该函数。

    但是,如果您出于某种原因确实想使用构造函数委托,那么在这种情况下,Ctx() 构造函数应该委托给 Ctx(RUN_MOD) 构造函数,而不是您最初尝试的相反方式,例如:

    class Ctx
    {
    public:
        enum RUN_MOD
        {
            MOD_RT,
            MOD_NRT,
        };
    
        Ctx(RUN_MOD runType)
        {
            if (runType == MOD_RT)
            {
                m_L = malloc(100);
                std::cout << "set m_L=" << m_L << std::endl;
            }
        }
    
        Ctx() : Ctx(MOD_RT) // <— here
        {
        }
    
        void print()
        {
            std::cout << "print() m_L=" << m_L << std::endl;
        }
    
    private:
        void *m_L = nullptr;
    
        const char* const ARG_TYPE_NOT_MATCH = "the type of argument is not match";
        const char* const ARG_NUM_INVALID = "the number of arguments is invalid";
        const char* const STACK_OPS_INPUT_ARG_INVALID = "the input argument passed to the stack ops is invalid";
    };
    

    【讨论】:

      【解决方案5】:

      调用任何类的 ctor 都会创建它的实例,在您发布的代码中,很明显在 Ctx() 中分配的 m_l 不属于由构造的对象Ctx(RUN_MOD runType)

      试试下面的代码

      void init_m_l()
      {
          m_L = malloc(100);
          std::cout << "set m_L=" << m_L << std::endl;
      }
      
      Ctx(RUN_MOD runType)
      {
          if(runType == MOD_RT)
             init_m_l();
      }
      
      Ctx()
      {
          init_m_l();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 2021-08-09
        相关资源
        最近更新 更多