my goal is to have only one board, no matter how many objects i make.
You are remarkably close to what you need.  The key idea still missing: how determine if this is the 1st ctor, so that you only init the static board a single time.  It turns out that a vector can solve this issue, too. 
#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock  HRClk_t; // std-chrono-hi-res-clk
typedef HRClk_t::time_point                 Time_t;  // std-chrono-hi-res-clk-time-point
typedef std::chrono::milliseconds           MS_t;    // std-chrono-milliseconds
typedef std::chrono::microseconds           US_t;    // std-chrono-microseconds
typedef std::chrono::nanoseconds            NS_t;    // std-chrono-nanoseconds
using   namespace std::chrono_literals;          // support suffixes like 100ms, 2s, 30us
#include <iostream>
#include <vector>
#include <cassert>
class myclass
{
private:
   static std::vector<int> board;
   static int              maxCol;
   // add non-static parameters (unique to each instance)
   // here
public:
   // ctor
   myclass(int maxRows=0, int maxCols=0)
      {
         // key idea: how determine 1st ctor, so only init board 1 time
         if(0 == board.size())
         {
            std::cout
               << "  because board.size() is 0, \n"
               "  we know this is the first opportunity "
               "to reserve and initialize \n  "
               << maxRows << "*" << maxCols << " = " << (maxRows * maxCols)
               << " elements." << std::endl;
            // reserve space
            board.reserve(maxRows*maxCols); // now have all the space needed
            // with space available, initialize the elements
            for (int r=0; r<maxRows; ++r) {
               for (int c=0; c<maxCols; ++c) {
                  board.push_back(0); // init to valid number
               }
            }
            maxCol = maxCols;
         } // additional invocation do not affect board, parameters ignored
         else
            std::cout << "\n\n  parameters ignored because size is ("
                      << board.size() << ")" << std::endl;
         // add myclass ctor unique actions here
      }
   ~myclass() = default;
   // 2d access game to board
   // to 1d           from-2d
   size_t    gbIndx(int r, int c) { return ((r * maxCol) + c); }
   // void   gbIndx(size_t indx1d, int& r, int& c) {
      // simple arithmetic to determine both r and c from indx1d
   //}
   int exec()
      {
         std::cout << "\n  exec(): sizeof(board) = " << sizeof(board)
                   << "  board.size() = " << board.size() << std::endl;
         // do what now?
         return(0);
      }
   // add more methods here
}; // class myclass
std::vector<int> myclass::board; // static vector
int              myclass::maxCol = 0;
int main(int, char**)
{
   myclass mc(10,10);
   Time_t start_us = HRClk_t::now();
   int retVal = mc.exec();
   // subsequent invocation work, but do not affect board.size()
   myclass mc2;
   mc2.exec();
   myclass mc3;
   mc3.exec();
   auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
   std::cout << "\n\n  t534.exec() duration  " << duration_us.count() << " us" << std::endl;
   return(retVal);
}
Output looks like:
because board.size() is 0, 
  we know this is the first opportunity to reserve and initialize 
  10*10 = 100 elements.
exec(): sizeof(board) = 24  board.size() = 100
parameters ignored because size is (100)
exec(): sizeof(board) = 24  board.size() = 100
parameters ignored because size is (100)
exec(): sizeof(board) = 24  board.size() = 100