0

My problem is as follows: I've got a class that holds a vector of another class that have to use random number generators. One way of implementation gives me a compile error 'error: use of deleted function ‘Ant::Ant(const Ant&)’ and a second approach gives me identical results in the repeated runs of the algorithm in main() using a for loop. If i run separate program instances, one after another, randomness is there (or seems to be).

Let me show you if i can.

EDIT: I am on Linux using GCC 7.5.0

One class holds a vector to a custom class and initialize as follow.

AntSystemSimple.h

class AntSystemSimple {
public:

    ...
private:
    std::vector<Ant> mAnts;
public:
   void init() 
    ...
};

AntSystem.cpp

AntSystemSimple::AntSystemSimple()
{
   ...
    mAnts.resize(1);
    ...
}

void AntSystemSimple::init() {
    this->setParameters();
    mAnts.resize(mNumOfAnts);
}

Ants.h

class Ant {
public:
    Ant();
    virtual ~Ant();

    void init(int numOfDestinations);
   void computeTour(...)
   ...

private:
   ...
    std::random_device randomDevice;
    std::mt19937_64 gen;
};

Ants.cpp

Ant::Ant():
...
*gen(randomDevice())*
{
...
}

void Ant::computeTour(...){
...
  std::uniform_real_distribution<double> dis(0.0, 1.0);
  double exceed = dis(gen);
...
}

First approach, that gives compile error 'error: use of deleted function ‘Ant::Ant(const Ant&)’ is the above. Eclipse shows the error at class Ant and required from class AntSystemSimple::ctor mAnts.resize(1) if it is any help.

Second approach, is to remove completely the randomDevice as member and initialize mt193737 as gen(std::random_device{}()). This compiles and works for consecutive calls of the compiled program. But if i ran the `main.cpp' like this:

AntSystemSimple antSystem;
for (int i = 0; i < repeat; ++i) {
        antSystem.init();
        antSystem.setInputDataMatrix(distances);
        antSystem.setParameters();

        antSystem.run();

        std::cout << "Best Length is: " << antSystem.getBestLength() << std::endl;
        printVectorInt("Best Path is: ", antSystem.getBestTour());
}

produces the same paths(randomness is the same) everytime.

I don't know if i described the problem enough, feel free to correct and ask any information. I would really like to undestand the problem here and what its causing it.

EDIT: Error at line mAnts.resize(1)

required from here
/usr/include/c++/7/bits/stl_construct.h:75:7: error: use of deleted function ‘Ant::Ant(const Ant&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/.../git/aco/src/AntSystemSimple.h:14:0,
                 from /home/.../git/aco/src/AntSystemSimple.cpp:8:
/home/.../git/aco/src/Ant.h:17:2: note: ‘Ant::Ant(const Ant&)’ is implicitly deleted because the default definition would be ill-formed:
  Ant(const Ant&) = default;

ERROR at line Ant(const Ant&) = default;

In file included from /usr/include/c++/7/random:49:0,
                 from /home/.../git/aco/src/Ant.h:12,
                 from /home/.../git/aco/src/AntSystemSimple.h:14,
                 from /home/.../git/aco/src/AntSystemSimple.cpp:8:
/usr/include/c++/7/bits/random.h:1619:5: note: declared here
     random_device(const random_device&) = delete;

`

Thank you a lot.

  • 1
    What compiler are you using? https://stackoverflow.com/questions/18880654/why-do-i-get-the-same-sequence-for-every-run-with-stdrandom-device-with-mingw – Retired Ninja Oct 07 '20 at 09:36
  • This question is really two problems in one. The first is solved by explicitly adding a copy constructor like so: `Ant(const Ant&) = default;` (or providing a custom copy constructor) – Botje Oct 07 '20 at 09:37
  • gCC 7.5.0 on linux. I should write that on the question – Xenakis Karamanos Oct 07 '20 at 09:39
  • Ok, i can try that, but what is that exactly and how does it solve it. I don't clearly understand the error produced. – Xenakis Karamanos Oct 07 '20 at 09:41
  • 1
    It means a `std::random` device is not copyable. You will need to write a custom copy constructor that fills that field with a different random_device. – Botje Oct 07 '20 at 09:48
  • 2
    I think you can solve both problems at once by creating a single global `std::random_device`, using it to seed the `std::mt19937_64` instances in your Ants, but *not* storing a separate random device per Ant. – Botje Oct 07 '20 at 09:49
  • I dont mind having a global but where should it go? On AntSystemSimple and give it as parameter to ant ctor? or on Ant class? – Xenakis Karamanos Oct 07 '20 at 10:00
  • A static variable in the `Ant` class sounds good, but it can be a standalone singleton variable as well. – Botje Oct 07 '20 at 10:05
  • Ok, i will. how do i initialize the generator with a static `random_device`? – Xenakis Karamanos Oct 07 '20 at 11:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222657/discussion-between-xenakis-karamanos-and-botje). – Xenakis Karamanos Oct 07 '20 at 11:36

1 Answers1

1

The problem is the random_device that is not copyable.

There are 3 solution:

  • Static Variable : you can define a static variable in the Ant class.
  • Singleton : you can define a singleton variable for the random_device
  • Global random_device : you can define a global variable for the random_device

The solution is not trivial, but you can adopt one of these above solution, as well as you programming style concerns.

Zig Razor
  • 3,381
  • 2
  • 15
  • 35
  • Ok that is understanble, but where does `random_device` get copied? Am i missing something – Xenakis Karamanos Oct 07 '20 at 10:58
  • Note: How do i initialize the generator with a static `random_device` member? – Xenakis Karamanos Oct 07 '20 at 11:07
  • The `random_device` is copied when an instance of class Ant is copied. – Zig Razor Oct 07 '20 at 12:32
  • For reference in how to initialize a static variable refer to this stackoverflow [question](https://stackoverflow.com/questions/5019856/initialize-static-variables-in-c-class) – Zig Razor Oct 07 '20 at 12:33
  • Hmm. I initialize in the header file outside of class and now i have an error of multiple definitions but can't find anything else about the definition. – Xenakis Karamanos Oct 07 '20 at 12:52
  • this linking error is caused by multiple include of the header file, and because you declare this static variable outside the class. (but this is another question) – Zig Razor Oct 07 '20 at 12:58
  • for more detail see https://stackoverflow.com/questions/49633230/linking-error-multiple-definition-of-static-variable – Zig Razor Oct 07 '20 at 12:58
  • Ok yes. Now it compiles. But the problem is still there. Running multiple times the algorithm produce the same paths. It alters only every after 1-2 seconds and in between is the same. – Xenakis Karamanos Oct 07 '20 at 13:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222665/discussion-between-zig-razor-and-xenakis-karamanos). – Zig Razor Oct 07 '20 at 13:27
  • 1
    Ok, found a logic bug where i would't clear the `bestTourLength` in `init()` and it would keep that best path in every run. Thanks for the input. Marked your answer as correct. – Xenakis Karamanos Oct 07 '20 at 13:31