Home > Software design >  How to use Objective-C sources' ExplicitInit class?
How to use Objective-C sources' ExplicitInit class?

Time:08-15

In the Objc source code, I found the following code. What is the meaning of this code and how to understand it?

objc/Project Headers/DenseMapExtras.h line:38

template <typename Type>
class ExplicitInit {
    alignas(Type) uint8_t _storage[sizeof(Type)];

public:
    template <typename... Ts>
    void init(Ts &&... Args) {
        new (_storage) Type(std::forward<Ts>(Args)...);
    }

    Type &get() {
        return *reinterpret_cast<Type *>(_storage);
    }
};

Below is my test code:

class MyC{
public:
    long l1;
    long l2;
    MyC(long _l1, long _l2){
        l1 = _l1;
        l2 = _l2;
    }
};
int main(){
    MyExplicitInit<MyC> e1 {};
    e1.init();
    return 0;
}

The compiler prompts the following error: enter image description here

CodePudding user response:

In the Objc source code, I found the following code. What is the meaning of this code and how to understand it?

To me it looks like a kind-of-factory which can be used as an alternative to the Construct On First Use Idiom. An instantiated class here represents a storage for an instance you can initialise and request when needed. As far as I understand it's not supposed to be used for local variables (it doesn't make much sense, despite being technically possible) and this is also suggested by the comments of code section with the said class template:

// We cannot use a C   static initializer to initialize certain globals because
// libc calls us before our C   initializers run. We also don't want a global
// pointer to some globals because of the extra indirection.
//
// ExplicitInit / LazyInit wrap doing it the hard way

For the error you are experiencing:

No matching operator new function for non-allocating placement new expression; include <new>

Assuming that you just added that piece of code somewhere in your own sources, the problem here is that you didn't include the <new> header. As simple as that - the error just says that you need to add #include <new> since so-called placement new is not part of the "default" C , it's an overloaded operator declared in this header.

Second, your init function expects arguments that matches one of the existing (non-aggregate) constructors of the given class, so you are expected to pass arguments which are either match the constructor parameters or can be implicitly converted to them: e1.init(1l, 2l)

A complete example looks something like this:

#include <_types/_uint8_t.h>
#include <new>

namespace objc {

    template <typename Type>
    class ExplicitInit {
        alignas(Type) uint8_t _storage[sizeof(Type)];

    public:
        template <typename... Ts>
        void init(Ts &&... Args) {
            new (_storage) Type(std::forward<Ts>(Args)...);
        }

        Type &get() {
            return *reinterpret_cast<Type *>(_storage);
        }
    };

};

struct sample_struct {
    long l1, l2;
    
    sample_struct(long _l1, long _l2): l1{_l1}, l2{_l2} {}
};

sample_struct& getInstance(bool should_init = false) {
    static objc::ExplicitInit<sample_struct> factory;
    if (should_init) {
        factory.init(1l, 2l);
    }
    return factory.get();
}
  • Related