0
#include <fstream>
#include <string_view>
#include <unordered_map>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
 
class Strategy {
private:
    int mActionNum;
    double mNormSum;
    double* mRegretSum;
    double* mStrategy;
    double* mStrategySum;
    double* mAverageStrategy;
 
public:
    Strategy (const int actionNum): mActionNum {actionNum} {
        mRegretSum = new double[actionNum];
        mStrategy = new double[actionNum];
        mStrategySum = new double[actionNum];
        mAverageStrategy = new double[actionNum];
 
        for (int a = 0; a < actionNum; ++a) {
            mRegretSum[a] = 0.0;
            mStrategy[a] = 1.0 / (double) actionNum;
            mStrategySum[a] = 0.0;
            mAverageStrategy[a] = 0.0;
        }
    }
 
    ~Strategy() {
        delete[] mRegretSum;
        delete[] mStrategy;
        delete[] mStrategySum;
        delete[] mAverageStrategy;
    }
 
    const double* get(const double weight) {
        mNormSum = 0.0;
 
        for (int a = 0; a < mActionNum; ++a) {
            mStrategy[a] = mRegretSum[a] > 0 ? mRegretSum[a] : 0;
            mNormSum += mStrategy[a];
        }
 
        for (int a = 0; a < mActionNum; ++a) {
            if (mNormSum > 0) {
                mStrategy[a] /= mNormSum;
            } else {
                mStrategy[a] = 1 / mNormSum;
            }
 
            mStrategySum[a] += weight * mStrategy[a];
        }
 
        return mStrategy;
    }
 
    const double* get_avg() {
        mNormSum = 0.0;
 
        for (int a = 0; a < mActionNum; ++a) {
            mNormSum += mStrategySum[a];
        }
 
        for (int a = 0; a < mActionNum; ++a) {
            if (mNormSum > 0) {
                mAverageStrategy[a] = mStrategySum[a] / mNormSum;
            } else {
                mAverageStrategy[a] = 1.0 / (double) mActionNum;
            }
        }
 
        return mAverageStrategy;
    }
};
 
 
int main () {
    std::ifstream f("/home/tomas/Dropbox/strategy.json");
    json data = json::parse(f);
 
    std::unordered_map<std::string_view, Strategy> strategies;
    std::string info_set {};
 
    for (auto& e : data) {
        info_set = e["cluster"].get<std::string>()
                    + ',' + e["history"].get<std::string>();
 
        Strategy strat { static_cast<int>(e["regret_sum"].size()) };
        strategies.insert({info_set, strat});
    }
    return 0;
}

I suppose that the problem is because the instance of the class is destroyed each every cycle, am I correct?

So I tried also something like this:

Strategy createOutOfScope(int size) {
    Strategy strat { size };
    return strat;
}

int main () {
    std::ifstream f("/home/tomas/Dropbox/strategy.json");
    json data = json::parse(f);

    std::unordered_map<std::string_view, Strategy> strategies;
    std::string info_set {};

    for (auto& e : data) {
        info_set = e["cluster"].get<std::string>()
                    + ',' + e["history"].get<std::string>();

        strategies.insert({info_set, createOutOfScope(static_cast<int>(e["regret_sum"].size()))});
    }
    return 0;
}

But of course, I haven't solved it. Can someone explain me how I can save a object in a unordered_map type, and generally how I can create and save an instance of object created out of scope. Thank you very much.

  • 6
    My first guess: `Strategy` is copied somewhere but you didn't overload the copy constructors, nor you deleted them. Thus, the pointers to the new-ed stuff are just flat copied (by the copy constructor generated by the compiler). Now, you have two instances with identical pointers -> two deletes of them (in their destructors). FYI: [Rule of 3/5/0](https://en.cppreference.com/w/cpp/language/rule_of_three) – Scheff's Cat Dec 14 '22 at 12:48
  • 2
    Any reason not to use `std::vector` for `mRegretSum` and all the other c-style arrays ? – wohlstad Dec 14 '22 at 12:52
  • Also use smart pointers or data objects instead of handling memory manually. unique_ptr should prevent the case @Scheff'sCat mentioned, so should std::vector – Simon Kraemer Dec 14 '22 at 12:53
  • 3
    @Scheff'sCat I guess the `strategies.insert({info_set, strat});` is making a copy of a local (temporary) object. Both would eventually be destroyed and, as you indicate, without the Rule of 3/3, that's causing the double deletion. – Adrian Mole Dec 14 '22 at 12:54
  • *I suppose that the problem is because the instance of the class is destroyed each every cycle, am I correct?* -- No, the problem is that your `Strategy` class is not safely copyable, and you are inserting unsafely copyable `Strategy` into the map. As mentioned, remove all of those `double*` pointers and use `std::vector`. Get rid of the `Strategy` destructor, return `std::vector&` from those functions that return `double*` now. Then the problem will be solved or close to being solved. – PaulMcKenzie Dec 14 '22 at 13:55
  • [This is an example](https://godbolt.org/z/chsj9sb63). – PaulMcKenzie Dec 14 '22 at 14:07
  • @PaulMcKenzie I think I'm in love with you. – ViciniVicini Dec 14 '22 at 14:41

0 Answers0