Skip to content

How to new an em-instance without INST.DELETE() and without memory LEAK? #20569

@haelue

Description

@haelue

I use embind and .smart_ptr_constructor() to bind a C++ class.

I suppose a smart-pointer could help me to write javascript easy without calling .delete(), but the browser console still warning:

xmc.js:1423 Embind found a leaked C++ instance Random <0x000113d8>.

Since .delete() is easily interrupted by exception or something else, how can I use emscripten really safe and concise?

My C++ header:

#ifndef RANDOM_H
#define RANDOM_H

#include <memory>

extern "C" {
    /**
     * @brief Generates random number.
    */
    class Random {
    private:
        long long seed;
    public:
        /**
         * @brief Construct randomizer using a seed.
         * WITH fixed-number to get false-random.
         * WITH timestamp to get real-random.
        */
        Random(double seed);
        int next();
        float nextFloat();
        double nextDouble();
    };

    std::shared_ptr<Random> newRandom(double seed);
}

#endif

My C++ soure:

#include "random.h"

Random::Random(double seed) {
    this->seed = (long long)seed;
    if (this->seed < 0) {
        this->seed = -this->seed;
    }
    if (this->seed >= 233280) {
        this->seed = this->seed % 233280;
    }
}

int Random::next() {
    this->seed = (this->seed * 9301 + 49297) % 233280;
    return this->seed;
}

float Random::nextFloat() {
    return (float) this->next() / 233280.0f;
}

double Random::nextDouble() {
    return (double) this->next() / 233280.0;
}

std::shared_ptr<Random> newRandom(double seed) {
    return std::make_shared<Random>(seed);
}

My embind wrapper:

#include "random.h"
#include <emscripten/bind.h>

using namespace emscripten;

EMSCRIPTEN_BINDINGS(module){
    class_<Random>("Random")
    .smart_ptr_constructor("Random", &std::make_shared<Random, double>)
    .function("next", &Random::next)
    .function("nextFloat", &Random::nextFloat)
    .function("nextDouble", &Random::nextDouble);
    function("newRandom", &newRandom);
}

My build command:

em++ --bind -O0 -s SINGLE_FILE=1 -s EXPORT_NAME=xmc -I include src/random.cpp js/em_bind/xmcwrap.cpp -o js/lib/xmc.js

My javascript test:

<script type="text/javascript" src="../lib/xmc.js"></script>
<script type="module">
      async function waitWasm() {
        return new Promise((resolve) => {
          if (Module["calledRun"]) {
            return resolve();
          }
          window.Module.onRuntimeInitialized = function() {
            return resolve();
          }
        });
      }

      await waitWasm();

      const rand = new Module.Random(new Date().getTime());

      const r3 = [];
      for (let i = 0; i < 10; i++) {
        r3.push(rand.next())
      }

      const r4 = [];
      for (let i = 0; i < 10; i++) {
        r4.push(rand.nextFloat())
      }

      const r5 = [];
      for (let i = 0; i < 10; i++) {
        r5.push(rand.nextDouble())
      }
      
      console.log(r3, r4, r5);
</script>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions