C++ 有没有办法在构造函数代码中初始化类的成员对象,而不是初始化器列表?

C++ 有没有办法在构造函数代码中初始化类的成员对象,而不是初始化器列表?,c++,memory,constructor,member,C++,Memory,Constructor,Member,考虑一下,我想在对象中封装一些库代码。该库需要通过调用该包装类的构造函数中的某些函数来设置和初始化 图书馆的“对象”然后分化为创建更多不同的“对象”,包装器类将其包装成另一个包装器对象的形式,该包装器对象应该是该类的普通成员 但在我看来,类的成员只能通过在构造函数的initializer列表中调用它们的构造函数来初始化或创建。这些代码的执行先于实际类的构造函数,该类初始化库及其环境,使我无法将该成员对象实际初始化为成员,而是强制我将其初始化为指向第二个包装器的指针,因为它的构造函数必须在第一个构

考虑一下,我想在对象中封装一些库代码。该库需要通过调用该包装类的构造函数中的某些函数来设置和初始化

图书馆的“对象”然后分化为创建更多不同的“对象”,包装器类将其包装成另一个包装器对象的形式,该包装器对象应该是该类的普通成员

但在我看来,类的成员只能通过在构造函数的initializer列表中调用它们的构造函数来初始化或创建。这些代码的执行先于实际类的构造函数,该类初始化库及其环境,使我无法将该成员对象实际初始化为成员,而是强制我将其初始化为指向第二个包装器的指针,因为它的构造函数必须在第一个构造函数的代码中手动调用

例如:

class A {
public:
    A() {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        ptr_to_some_library_metadata *a = library_function(); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */
        //initialize b
    }
private:
    B b; //Wants to be a member but can not
};

class B {
    B(ptr_to_some_library_metadata *a);
}

初始值设定项列表用于使用默认构造函数以外的其他构造函数

但是,创建自定义函数将初始化
b

class A {
public:
    A():b(init()) {
    }
private:
    B b; //Wants to be a member but can not

    static B init()
    {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        ptr_to_some_library_metadata *a = library_function(); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */

        return B(a);
    }
};

初始值设定项列表用于使用默认构造函数以外的其他构造函数

但是,创建自定义函数将初始化
b

class A {
public:
    A():b(init()) {
    }
private:
    B b; //Wants to be a member but can not

    static B init()
    {
        if(!wrapped_library_init()) {
            exit(CRITICAL_ERROR);
        }
        ptr_to_some_library_metadata *a = library_function(); /*Needs to
        be called after wrapped_library_init() or needs a pointer to some
        wrapped object created inside this constructor */

        return B(a);
    }
};

成员对象只能在成员初始值设定项列表中构造。有几种技术可用于初始化对象,不过:

  • 在返回合适的对象之前,使用helper[lambda]函数执行必要的额外工作。例如:

    A()
          : B([]{
              if (!wrapped_library_init()) {
                  exit(CRITICAL_ERROR);
              }
              return library_function();
          }()) {
    }
    
    class A {
        union Bu { B b };
        Bu b;
    public:
        A() {
            if (!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            new(&b.b) B(library_function());
        }
        ~A() {
            b.b.~B();
        }
        // ...
    };
    
  • 您可以通过仅与适当的成员使用
    联合
    来延迟构造。使用此技术时,需要显式销毁成员,例如:

    A()
          : B([]{
              if (!wrapped_library_init()) {
                  exit(CRITICAL_ERROR);
              }
              return library_function();
          }()) {
    }
    
    class A {
        union Bu { B b };
        Bu b;
    public:
        A() {
            if (!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            new(&b.b) B(library_function());
        }
        ~A() {
            b.b.~B();
        }
        // ...
    };
    

  • 我个人会使用第一种方法。但是,在某些情况下,使用
    联合来延迟构造是有帮助的。

    成员对象只能在成员初始值设定项列表中构造。有几种技术可用于初始化对象,不过:

  • 在返回合适的对象之前,使用helper[lambda]函数执行必要的额外工作。例如:

    A()
          : B([]{
              if (!wrapped_library_init()) {
                  exit(CRITICAL_ERROR);
              }
              return library_function();
          }()) {
    }
    
    class A {
        union Bu { B b };
        Bu b;
    public:
        A() {
            if (!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            new(&b.b) B(library_function());
        }
        ~A() {
            b.b.~B();
        }
        // ...
    };
    
  • 您可以通过仅与适当的成员使用
    联合
    来延迟构造。使用此技术时,需要显式销毁成员,例如:

    A()
          : B([]{
              if (!wrapped_library_init()) {
                  exit(CRITICAL_ERROR);
              }
              return library_function();
          }()) {
    }
    
    class A {
        union Bu { B b };
        Bu b;
    public:
        A() {
            if (!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            new(&b.b) B(library_function());
        }
        ~A() {
            b.b.~B();
        }
        // ...
    };
    

  • 我个人会使用第一种方法。但是,在某些情况下,使用
    联合来延迟构造是有帮助的。

    将库包装在类中:

    class LibraryWrapper
    {
    public:
        LibraryWrapper()
        {
            if(!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            lib_data.reset(library_function()); /*Needs to
            be called after wrapped_library_init() or needs a pointer to some
            wrapped object created inside this constructor */
        }
        //~LibraryWrapper() {/**/}
        //LibraryWrapper(const LibraryWrapper&) {/**/}            // =delete; ?
        //LibraryWrapper& operator=(const LibraryWrapper&) {/**/} // =delete; ?
    
    //private: // and appropriate interface to hide internal
        std::unique_ptr<ptr_to_some_library_metadata, CustomDeleter> lib_data;
    };
    
    class B {
    public:
        explicit B(ptr_to_some_library_metadata *a);
        // ...
    };
    

    将库包装在类中:

    class LibraryWrapper
    {
    public:
        LibraryWrapper()
        {
            if(!wrapped_library_init()) {
                exit(CRITICAL_ERROR);
            }
            lib_data.reset(library_function()); /*Needs to
            be called after wrapped_library_init() or needs a pointer to some
            wrapped object created inside this constructor */
        }
        //~LibraryWrapper() {/**/}
        //LibraryWrapper(const LibraryWrapper&) {/**/}            // =delete; ?
        //LibraryWrapper& operator=(const LibraryWrapper&) {/**/} // =delete; ?
    
    //private: // and appropriate interface to hide internal
        std::unique_ptr<ptr_to_some_library_metadata, CustomDeleter> lib_data;
    };
    
    class B {
    public:
        explicit B(ptr_to_some_library_metadata *a);
        // ...
    };
    

    对于案例2,
    std::optional
    而不是拥有5/3/0自由规则的联合(否则创建一个类“
    delayed_-construct
    ”,以避免
    optional
    的开销)。@Jarod42:我不愿意为
    std::optional
    的需要指明是否设置了它而付费。但是,我同意延迟的构造可以合理地考虑到类模板中。另一方面,我的经验是,包装类无论如何都会成为资源管理器,因为它们通常需要特殊的初始化和销毁。我的主要观点是强调要实现的不仅仅是析构函数,还有--copy--/assignment/move。正如我在你的帖子中发现的那样(可能包含在
    /…
    中)。所以懒惰的人可以支付开销:-)对于案例2,
    std::optional
    ,而不是拥有5/3/0自由规则的联合(否则创建一个类“
    delayed_-construct
    ”,以避免
    optional
    )的开销。@Jarod42:我不愿意为
    std::optional
    的需要指出它是否被设置而付费。但是,我同意延迟的构造可以合理地考虑到类模板中。另一方面,我的经验是,包装类无论如何都会成为资源管理器,因为它们通常需要特殊的初始化和销毁。我的主要观点是强调要实现的不仅仅是析构函数,还有--copy--/assignment/move。正如我在你的帖子中发现的那样(可能包含在
    /…
    中)。所以懒惰的人可以支付管理费用:-)