Initializing a Large Global Constant Object

How do you use a file to initialize a global const const object that is too large to be created on the stack? This is my attempt:

// test.h
#pragma once
#include <boost/array.hpp>

typedef boost::array<int,100000> bigLut_t;
extern const bigLut_t constLut;

// test.cpp
#include <fstream>
#include <boost/filesystem.hpp>
#include "test.h"

bigLut_t& initializeConstLut()
{
    if( boost::filesystem::exists("my_binary_file") == false ) {
        std::ofstream outStream( "my_binary_file", ios::out | ios::binary );
        bigLut_t* tempLut = new bigLut_t;
        for(int i = 0; i < 100000; ++i) {
            // Imagine this taking a long time,
            // which is why we're using a file in the first place
            tempLut->at(i) = i;
        }
        outStream.write( reinterpret_cast<char*>(tempLut), sizeof(bigLut_t) );
        outStream.close();
        delete tempLut;
    }
    // We can't write "bigLut_t lut;" because that would cause a stack overflow
    bigLut_t* lut = new bigLut_t; // lut gets never deallocated
    std::ifstream inStream( "my_binary_file", ios::in | ios::binary );
    inStream.read( reinterpret_cast<char*>(lut), sizeof(bigLut_t) );
    inStream.close();
    return *lut;
}

const bigLut_t constLut = initializeConstLut();

AFAIK this works in a sense that constLut gets root initialization, but there is a memory leak, since bigLut_t * lut is never freed. I tried using a smart pointer for this, but this led to the fact that the values โ€‹โ€‹in constLut were pretty random. I am puzzled by the lack of information I found while trying to find a Google solution.

+3
source share
6 answers

How did you use shared_ptr? Try the following:

// test.h
#pragma once
#include <boost/array.hpp>

typedef boost::array<int,100000> bigLut_t;
extern const bigLut_t constLut;

// test.cpp
#include <fstream>
#include <boost/filesystem.hpp>
#include "test.h"

boost::shared_ptr<bigLut_t> initializeConstLut()
{
    if( boost::filesystem::exists("my_binary_file") == false ) {
        std::ofstream outStream( "my_binary_file", ios::out | ios::binary );
        bigLut_t* tempLut = new bigLut_t;
        for(int i = 0; i < 100000; ++i) {
            // Imagine this taking a long time,
            // which is why we're using a file in the first place
            tempLut->at(i) = i;
        }
        outStream.write( reinterpret_cast<char*>(tempLut), sizeof(bigLut_t) );
        outStream.close();
        delete tempLut;
    }
    // We can't write "bigLut_t lut;" because that would cause a stack overflow
    boost::shared_ptr<bigLut_t> lut(new bigLut_t); // lut gets never deallocated
    std::ifstream inStream( "my_binary_file", ios::in | ios::binary );
    inStream.read( reinterpret_cast<char*>(lut), sizeof(bigLut_t) );
    inStream.close();
    return lut;
}

const bigLut_t constLut = *(initializeConstLut().get());
+2

. , , ( , - ;). .

Meyers, static , :

inline BigThing const& theBigThing()
{
    static BigThing const theInstance;    // Default constructor does the init job.
    return theInstance;
}

, , , , --:

namespace detail {
    inline BigThing const& theBigThing()
    {
        static BigThing const theInstance;    // Default constructor does the init job.
        return theInstance;
    }
}

BigThing const& theBigThing = detail::theBigThing();    // No copying, just ref.

, BigThing - , , . , - . , ( , , ):

namespace detail {

    struct BigThingWrapper
    {
        BigThing  thingy_;

        BigThingWrapper()
        {
            // Initialize the thingy_ member here.
        }
    };

    inline BigThing const& theBigThing()
    {
        static BigThingWrapper const theInstance;
        return theInstance.thingy_;
    }
}

BigThing const& theBigThing = detail::theBigThing();    // No copying, just ref.

1: inline, . , .

2: ERORS, TYPPOS -.:-) , .

3: , , , "", "" , "".

hth.,

+2

, new initializeConstLut ?

, , / . , :

  • ( )
  • , , Singleton . , const .

, (, ).

+1

, - , - :

// test.h
#pragma once
#include <boost/array.hpp>

typedef boost::array<int,100000> bigLut_t;
extern const bigLut_t& constLut; // make it a reference

// test.cpp
#include <fstream>
#include <boost/filesystem.hpp>
#include "test.h"

namespace {
    std::auto_ptr<bigLut_t> initializeConstLut()
    {
        std::auto_ptr<bigLut_t> lut(new bigLut_t); 

        if( boost::filesystem::exists("my_binary_file") == false ) {
            std::ofstream outStream( "my_binary_file", ios::out | ios::binary );

            for(int i = 0; i < 100000; ++i) {
                // Imagine this taking a long time,
                // which is why we're using a file in the first place
                lut->at(i) = i;
            }

            outStream.write( reinterpret_cast<char*>(lut), sizeof(bigLut_t) );
            outStream.close();

            // no point writing then reading the same data
        } else {            
            std::ifstream inStream( "my_binary_file", ios::in | ios::binary );
            inStream.read( reinterpret_cast<char*>(lut.get()), sizeof(bigLut_t) );
            inStream.close();
        }

        return lut;
    }

    // local to this compilation unit, deletes object on exit
    std::auto_ptr<bigLut_t> constLutPtr ( initializeConstLut() );
}

// the extern reference refers to the object held by the auto_ptr
const bigLut_t& constLut ( *constLutPtr.get() );

, , , , , , , (& constLutPtr , ).

constLut , , , , - const_cast constLutPtr. reinterpret_cast<char*>(const_cast<bigLut_t*>(&constLut)) .

+1

, , . , , ( , , DB ), . , , : .

0

. , . :

  void destroyLut(bigLut_t& lut)
  {
      delete &lut;
  }

Then just call this function before exiting main. You should never rely on static initialization and destruction in C ++. It is always best to do explicit initialization and destruction.

0
source

Source: https://habr.com/ru/post/1777159/


All Articles