Click here to Skip to main content
15,881,852 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
     Is there a way to have this initialization block similar to Java that we could implement and run properly in C++.

There were two types of init-block in Java:
1. init-block/raw-init-block, this will invoke at every new instance created.
2. static-init-block, this will only invoke once and consistently the first to be run/invoke before the init-block(if you implemented it).


What I have tried:

But the problem is, it kinds of behaving like a raw-init-block/init-block if were not using this pass-by-reference syntax.

First, We have this custom header file: static_init_block.h, I found this at IDEONE.COM: https://ideone.com/6sjRzz[^]
#ifndef __STATIC_INIT_BLOCK_H__
#define __STATIC_INIT_BLOCK_H__

#define __CONCATE(X,Y) X##Y
#define __CONCATE_IMPL(X,Y) __CONCATE(X,Y)
#define __UNIQUE(NAME) __CONCATE_IMPL(NAME, __LINE__)

struct StaticInitBlock final {
	template<typename T> 
	constexpr StaticInitBlock(const T& only_once) {
		only_once(); 
	}
	//REM: to counter "warning: unused variable"
	constexpr ~StaticInitBlock() { /**REM: ignore */ }
};
//REM: `__UNIQUE(...)` macro required if we expect multiple `static-init` blocks in function
#define __STATIC StaticInitBlock __UNIQUE(block) = [&]() -> void

#endif //REM: end of __STATIC_INIT_BLOCK_H__


And then we use that header file inside of this module partition interface: *.ixx
And include that as a global module fragment.
Note: I did not show the implementation of this module, since this is a straightforward src-code
module; //REM: global module fragment
#include "static_init_block.h"

export module domain.name:module_partition_name;

import <iostream>; //REM: header unit

namespace domain::name {
    namespace module_partition_name {
        export class ClassBase {
            __STATIC { //REM: static-init-block
                std::cout << "in namespace module_partition_name ClassBase static init block" << std::endl;
            };
        public:
            ClassBase();
            virtual ~ClassBase();
        };
        export class ClassDerive : public ClassBase {
            __STATIC { //REM: static-init-block
                std::cout << "in namespace module_partition_name ClassDerive static init block" << std::endl;
            };
        public:
            ClassDerive();
            virtual ~ClassDerive() override;
        };
    }
}

export namespace $DN_MODULE_PARTITION_NAME = domain::name::module_partition_name;
export typedef   $DN_MODULE_PARTITION_NAME::ClassBase   ClassBase_t;
export typedef   $DN_MODULE_PARTITION_NAME::ClassDerive ClassDerive_t;


primary module interface: *.ixx
export module domain.name;
export import :module_partition_name;



and at the main entry function: *.cxx
//REM: we must import domain.name;


//REM: RAI Initialization
//REM: the static-init-block did not work its act like a raw-block/init-block
ClassDerive_t d0;
ClassDerive_t d1;
ClassDerive_t d2;
//REM: explicitly allocate memory in ~HEAP, the static-init-block did not work.
//REM: and again it behave like an init-block.
ClassDerive_t* d00 = new ClassDerive_t();
ClassDerive_t* d01 = new Classderive_t();
ClassDerive_t* d02 = new ClassDerive_t();
delete ...;

//REM: Below this, the static-init-block works as intended. However
//REM: We don't want to run it such like this only using/sharing one address
//REM: in the real world this is impossible to maintain,
//REM: cuz we always need unique instances to keep data in tracks.
//REM: PASS-BY-REFERENCE
ClassDerive_t d000;
ClassDerive_t* d001 = &d000;
...
//REM: ~HEAP, PASS-BY-REFENCE
ClassDerive_t* d0000 = new ClassDerive_t();
ClassDerive_t* d0001 = d0000;
...
delete ...;
Posted
Updated 22-May-22 3:03am
v11
Comments
Stefan_Lang 5-Jan-22 8:25am    
You haven't mentioned what kind of problem you intend to solve, or why using modules prevents you from doing it with standard C++ techniques. Nor have you mentioned what functionality of Java initialization blocks you intend to recreate in C++.

I fail to see the need for this, or the problem you set out to solve: Constructors can - and should - do all of this for you, out of the box.

I expanded on that in my solution. It may not be the solution to your question, but it is most certainly a better way to approach this topic.

You could probably simplify that by the use of the singleton pattern - Google Search[^].
 
Share this answer
 
What I did for now was to call/invoked it inside of the first line of one of any constructor, Note: upon by doing it we need to have a delegated constructor if we do had multiple overloaded constructors, so that we could link it together, then put this static block to the last linked constructor to had a chance running it only once and will be invoke first before any other else. But first we do need to add a static keyword found at the header file: static_init_block.h 3rd to the last line which is a STATIC REGISTRATION MACRO, #define __STATIC static StaticInitBlock __UNIQUE(block) = [&]() -> void

PS: I did not try/implement it yet to the bigger projects, but we had an assumption that this will cause an overhead more specifically at the delegated constructor(s);

//REM: overview or in theory
class ClassOne {
public:
    ClassOne() {
        __STATIC {
            std::cout << "ClassOne, STATIC init block" << std::endl;
        };
        //REM: second statement ...
    }
};


//REM: Overloaded Constructor, I use delagation constructor
class ClassOne {
public:
    //REM: delegating constructor
    ClassOne() : ClassOne(0) {
        //REM: statement
    }
    //REM: the last linked constructor
    ClassOne(int param0) {
        __STATIC {
            std::cout << "ClassOne, STATIC init block" << std::endl;
        };
        //REM: second statement;
    }
};


If we want simulated/similar to init-block then add this line/syntax:
#define __INIT StaticInitBlock __UNIQUE(block) = [&]() -> void at the header file which was next to the other defined STATIC REGISTRATION MACRO.
 
Share this answer
 
v8
You seem to try and imprint another languages' properties onto C++, and that is never a good idea!

My experience with java is limited, and I'm not sure what you actually have in mind, but the code you posted is clearly not the recommended way of doing things in C++. Most importantly, C/C++ does have a main function that can create it's own objects, without being part of an object: that is where you create the basic entities of your program, not in a some static intialization!

Initializing an object statically makes sense only for some classes in C++. For most, creating an object without tangible data is not helping anyone. This is bad for multiple reasons:

(a) you needlessly spend time trying to fill an object with data without having data

(b) you needlessly spend effort passing references of meaningless objects across your code until you get to the point where you can actually fill it with meaning.

(c) You later need to initialize it again. And you need to keep track of which objects need this initialization, and which don't.

(d) you confuse readers of your code by moving around references of objects that aren't valid objects

(e) you introduce additional sources of errors by providing references to objects that are not actually initilized with meaningful values: anyone dealing with these references either needs to spend additional effort just to detect whether the object it is looking at is actually valid, or else risk undefined behaviour.


What you should do instead is create each object right before you use it, because that is the time when you have all the information that you need to create a valid object - indeed you must have all the information at that point, because otherwise you may not use it! And then you provide contructors or factory methods to construct this object from this information.


Disclaimer: As always, there are exceptions. But for the many reasons outlined above, you should avoid static initialization as much as possible, and prefer construction and initialization with relevant data at the exact place and time when the object is needed.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900