No exceptions C++ and partially constructed objects

Looking over Joint Strike Fighter Air Vehicle C++ Coding Standard, rule AV 73 states something on the lines: Default c++ constructors should be avoided if that means leaving object in a partially constructed place. This is obvious a good advice but things get complicated when you also disallow exceptions (as it does)

I wonder if they also try to give something else in return to make it practical. E.g. following example needs 2 faze construction if OUT_OF_MEMORY has to be handled (but the problem is more general of course)

class A {
    A() = default; // no way to report construction of B and C
    int Init(); // allocation failure of B/C can be reported only here
    private:
    B* b;
    C* c
}

One way to handle the problem is to have a A* Create() static member but in this case A has to free store allocated or keep an non-fully initialized state inside A and check it inside every member access, which seems not better at all than using a C style

int Initialize(A& out) // stack allocation
int Initialize(unique_ptr<A>& out) // free store allocation

EDIT I posted one possible approach bellow also. I took under consideration that dynamic memory allocation is necessary and the fact that any errors can happen while fully constructing an object. This is a scenario that is plausible for any driver development work.

3

Mandatory disclaimers

(1) Because people who have seen the code can’t say anything about it, and people who can freely comment on it have never seen the actual code, all we can do here is to speculate, speculate, and to speculate. Therefore, here is not an answer, just a speculation.

(2) This is not the typical way I write C++ because most of the projects I work on allows exceptions, at least on a local basis (i.e. not crossing application boundaries), and the coding standard ensures that there are always appropriate exception catchers in the right place. This answer was written as if it is an interesting thought, not as a sharing of experience.


My opinion is that to avoid the issue of partially constructed object (or, “state”), one must first fundamentally change the way parameter (precondition) validation is performed.

The change is this: instead of validating and assigning parameters one-by-one, one must perform the complete validation of all parameters together, in a side-effect-free manner.

In addition to that change, the role of class constructor is also changed. Instead of handling both precondition validation and state initialization, it will “outsource” both to someone else; it will only retain the part of responsibilities that are “failproof” (not capable of failing).

For example, assigning a primitive value (e.g. integer) to a primitive variable is failproof, provided that the primitive variable has valid storage. Another example is the ownership-transfer of a pointer from one smart variable to another.

Some of the biggest advances of C++11 is that smart pointers (and many other things) are moving toward making at least some of the operations “failproof”, by giving the option of isolating those “failable” (having the potential of failing) operations into separate methods.


Ultimately, however I must say, the “no exceptions” rule is sometimes impractical for at least some types of application development. How else would one prevent std::bad_alloc without exceptions? Should the system crash-and-burn?

Mission-critical systems prevent out-of-memory issues by ensuring system-wide determinism in memory usage. Everything is preallocated; objects are merely placement-newed on allocators. There is a maximum number of instances prescribed for each type of objects; attempt to exceed the maximum will either be rejected, or result in the yanking of another less-important, not-actively-in-use object.

This, may be why we keep hearing those memes about “this enemy tracking system is capable of simultaneously tracking 256 different objects.” When a 257th object wants to be added to the system, one of the least-important object must go. Since none of us commenting here have seen any of the code, this is just a speculation.

4

Default c++ constructors should be avoided if that means leaving object in a partially constructed place. This is obvious a good advice but things get complicated when you also disallow exceptions (as it does)

Not necessarily. Consider these rules:

  • a constructor should receive already validated arguments, and perform no operations outside of initializations/movement of values (constructor’s responsibility is to initialize the object, not to compute values, then initialize the object – that would break SRP).

  • if an object’s construction is non-trivial, computational part should be moved into a factory function

Example implementation:

class A {
public:
    A() = deleted; // no way to construct instance that completely initializes A

    // int Init(); // don't use two-phased construction; it imposes on client code

    A(B* b, C* c) : b_{ b }, c_{ c } {}

private:
    B* b_;
    C* c_;
};

enum result { success, error };

// return error code
result make_A(B_and_Q_store& store, A*& instance)
{
    B * b = store.buy_a_b();
    C * c = store.get_q().make_a_c();
    if(!C)              // ERROR HANDLING
        return error;   // ERROR HANDLING
    instance = new A{ b, c };
    return success;
}

Client code:

A* a = nullptr;
if(success == make_A(some_store, a)) // ERROR HANDLING
{
    // ...
}

This implementation offers convenience and good design for client code:

  • make_A performs failable computations;

  • constructor contains only trivial code;

  • law of demeter is respected: because an instance of A only uses B and C, it shouldn’t know (or depend on) how B and C are constructed (because it is no longer responsible for instantiating them).

Similar to what @rwong states (when he mentions side effects and validation), parameter/argument values are validated as necessary, before you create the A instance (that is, when you get to creating the instance, you already know all parameter values are valid).

6

One way to handle these is to have factory functions:

expected<Missile> Missile::Create(Params...)
expected<unique_ptr<Missile>> Missile::Create(Params...)

class Missile {
  private:
   Missile() = default;
   int Initialize(int power) // second phase constructor {
     // other operations (besides out_of_memory) that may fail
     // can be reported from this function
     expected<PowerSupply> expectedPower = PowerSupply::Create(power);
     if (!expectedPower.valid()) {
       return expectedPower.get_error();
     }
     this->power = std::move(expectedPower); // from now on power.valid() true
     return SUCCESS;

  public:
  static expected<Missile> Missile::Create(int p) {
    // 1. call default constructor first, this is automatic
    // storage so no fail
    // 2. Initialize called. 
    // If failure - report expected<Missile>::from_error(Initialize_STATUS);
    Missile m;
    auto status = m.Initialize(p);
    if (status != 0) return expected<Missile>::from_error(status);
    return Missile; // implicit conversion from T to expected<T>
  }
  static expected<unique_ptr<Missile>> Missile::Create(int p) {
    // 1. use operator new to construct - may fail -> expected::from_error(OUT_OF_MEMMORY)
    // 2. call Initialize and possibly report second phase errors
  }

  private:
  int power;
  expected<PowerSupply> power;
}

This is cleaner than using out parameters and a complex object is able (using 2 phases) to build it’s dependencies, be it as automatic variable or free store allocated.

Class expected default constructor only allocates automatic storage for T. One can create an initialized expected instance by assigning a T instance to expected<T>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

No exceptions C++ and partially constructed objects

Looking over Joint Strike Fighter Air Vehicle C++ Coding Standard, rule AV 73 states something on the lines: Default c++ constructors should be avoided if that means leaving object in a partially constructed place. This is obvious a good advice but things get complicated when you also disallow exceptions (as it does)

I wonder if they also try to give something else in return to make it practical. E.g. following example needs 2 faze construction if OUT_OF_MEMORY has to be handled (but the problem is more general of course)

class A {
    A() = default; // no way to report construction of B and C
    int Init(); // allocation failure of B/C can be reported only here
    private:
    B* b;
    C* c
}

One way to handle the problem is to have a A* Create() static member but in this case A has to free store allocated or keep an non-fully initialized state inside A and check it inside every member access, which seems not better at all than using a C style

int Initialize(A& out) // stack allocation
int Initialize(unique_ptr<A>& out) // free store allocation

EDIT I posted one possible approach bellow also. I took under consideration that dynamic memory allocation is necessary and the fact that any errors can happen while fully constructing an object. This is a scenario that is plausible for any driver development work.

3

Mandatory disclaimers

(1) Because people who have seen the code can’t say anything about it, and people who can freely comment on it have never seen the actual code, all we can do here is to speculate, speculate, and to speculate. Therefore, here is not an answer, just a speculation.

(2) This is not the typical way I write C++ because most of the projects I work on allows exceptions, at least on a local basis (i.e. not crossing application boundaries), and the coding standard ensures that there are always appropriate exception catchers in the right place. This answer was written as if it is an interesting thought, not as a sharing of experience.


My opinion is that to avoid the issue of partially constructed object (or, “state”), one must first fundamentally change the way parameter (precondition) validation is performed.

The change is this: instead of validating and assigning parameters one-by-one, one must perform the complete validation of all parameters together, in a side-effect-free manner.

In addition to that change, the role of class constructor is also changed. Instead of handling both precondition validation and state initialization, it will “outsource” both to someone else; it will only retain the part of responsibilities that are “failproof” (not capable of failing).

For example, assigning a primitive value (e.g. integer) to a primitive variable is failproof, provided that the primitive variable has valid storage. Another example is the ownership-transfer of a pointer from one smart variable to another.

Some of the biggest advances of C++11 is that smart pointers (and many other things) are moving toward making at least some of the operations “failproof”, by giving the option of isolating those “failable” (having the potential of failing) operations into separate methods.


Ultimately, however I must say, the “no exceptions” rule is sometimes impractical for at least some types of application development. How else would one prevent std::bad_alloc without exceptions? Should the system crash-and-burn?

Mission-critical systems prevent out-of-memory issues by ensuring system-wide determinism in memory usage. Everything is preallocated; objects are merely placement-newed on allocators. There is a maximum number of instances prescribed for each type of objects; attempt to exceed the maximum will either be rejected, or result in the yanking of another less-important, not-actively-in-use object.

This, may be why we keep hearing those memes about “this enemy tracking system is capable of simultaneously tracking 256 different objects.” When a 257th object wants to be added to the system, one of the least-important object must go. Since none of us commenting here have seen any of the code, this is just a speculation.

4

Default c++ constructors should be avoided if that means leaving object in a partially constructed place. This is obvious a good advice but things get complicated when you also disallow exceptions (as it does)

Not necessarily. Consider these rules:

  • a constructor should receive already validated arguments, and perform no operations outside of initializations/movement of values (constructor’s responsibility is to initialize the object, not to compute values, then initialize the object – that would break SRP).

  • if an object’s construction is non-trivial, computational part should be moved into a factory function

Example implementation:

class A {
public:
    A() = deleted; // no way to construct instance that completely initializes A

    // int Init(); // don't use two-phased construction; it imposes on client code

    A(B* b, C* c) : b_{ b }, c_{ c } {}

private:
    B* b_;
    C* c_;
};

enum result { success, error };

// return error code
result make_A(B_and_Q_store& store, A*& instance)
{
    B * b = store.buy_a_b();
    C * c = store.get_q().make_a_c();
    if(!C)              // ERROR HANDLING
        return error;   // ERROR HANDLING
    instance = new A{ b, c };
    return success;
}

Client code:

A* a = nullptr;
if(success == make_A(some_store, a)) // ERROR HANDLING
{
    // ...
}

This implementation offers convenience and good design for client code:

  • make_A performs failable computations;

  • constructor contains only trivial code;

  • law of demeter is respected: because an instance of A only uses B and C, it shouldn’t know (or depend on) how B and C are constructed (because it is no longer responsible for instantiating them).

Similar to what @rwong states (when he mentions side effects and validation), parameter/argument values are validated as necessary, before you create the A instance (that is, when you get to creating the instance, you already know all parameter values are valid).

6

One way to handle these is to have factory functions:

expected<Missile> Missile::Create(Params...)
expected<unique_ptr<Missile>> Missile::Create(Params...)

class Missile {
  private:
   Missile() = default;
   int Initialize(int power) // second phase constructor {
     // other operations (besides out_of_memory) that may fail
     // can be reported from this function
     expected<PowerSupply> expectedPower = PowerSupply::Create(power);
     if (!expectedPower.valid()) {
       return expectedPower.get_error();
     }
     this->power = std::move(expectedPower); // from now on power.valid() true
     return SUCCESS;

  public:
  static expected<Missile> Missile::Create(int p) {
    // 1. call default constructor first, this is automatic
    // storage so no fail
    // 2. Initialize called. 
    // If failure - report expected<Missile>::from_error(Initialize_STATUS);
    Missile m;
    auto status = m.Initialize(p);
    if (status != 0) return expected<Missile>::from_error(status);
    return Missile; // implicit conversion from T to expected<T>
  }
  static expected<unique_ptr<Missile>> Missile::Create(int p) {
    // 1. use operator new to construct - may fail -> expected::from_error(OUT_OF_MEMMORY)
    // 2. call Initialize and possibly report second phase errors
  }

  private:
  int power;
  expected<PowerSupply> power;
}

This is cleaner than using out parameters and a complex object is able (using 2 phases) to build it’s dependencies, be it as automatic variable or free store allocated.

Class expected default constructor only allocates automatic storage for T. One can create an initialized expected instance by assigning a T instance to expected<T>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật