mardi 31 janvier 2023

Why trying to print unicode encoded strings with cout leads to compilation error in newer C++ standards?

I tried the following printing of Unicode characters with Visual C++ 2022 Version 17.4.4 with C++ standard set to the latest.

#include <iostream>

using namespace std;

int main()
{
  cout << u8"The official vowels in Danish are: a, e, i, o, u, \u00E6, \u00F8, \u00E5 and y.\n";
  return 0;
}

I have the compilation error:

1>C:\projects\cpp\test\test.cpp(7,8): error C2280: 'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char8_t *)': attempting to reference a deleted function
1>C:\projects\cpp\test\test.cpp(7,8): error C2088: '<<': illegal for class

The same behavior is observed with u (utf-16) and U (utf-32) string literals.

Setting the standard to C++17 or C++14 makes the program to compile.

What is the rationale for disallowing this code in C++20 and later standards and what is the correct way to print Unicode string literals in those standards?

Pybind11 - ImportError: .../pybindx.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN6google8protobuf8internal26fixed_address_empty_stringB5cxx11E

I wrote some binding code to bind C++ code with python in pybindx.cpp file. I want to call some functions (implemented in C++) using python. When I use python setup.py build_ext command, the .so file ./build/lib.linux-x86_64-3.8/pybindx.cpython-38-x86_64-linux-gnu.so is getting created, but when I try to import(import pybindx) in test.py to call binded functions, It gives the following error:

ImportError: <path-to-.so-file>/pybindx.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN6google8protobuf8internal26fixed_address_empty_stringB5cxx11E

I have added <path-to-.so-file> to PYTHONPATH and LD_LIBRARY_PATH.

My setup.py file contains following code:

import os, sys
from distutils.core import setup, Extension
from distutils import sysconfig

cpp_args = ['-std=c++11']

ext_modules = [
    Extension(
        'pybindx',
        ['class1.cpp', 'class2.cpp', 'base_class1.cpp', 'base_class2.cpp', 'pybindx.cpp'],
        include_dirs=['paths/to/include/header/files', 'path/to/protobuf/include'],
        language='c++',
        extra_compile_args = cpp_args,
    ),
]
setup(
    name='pybindx',
    version='0.0.1',
    author='xxxxx',
    author_email='xxxxx',
    description='desc',
    ext_modules=ext_modules,
)

Where, class1.cpp, class2.cpp, base_class1.cpp, base_class2.cpp are the files having implementation of classes and functions which I want to bind with python.

I am new to pybind11, can someone help me with this? Thanks!

I tried writing small example code without protobuf, where I am able to call the C++ function using test.py, but here I want to use protobuf.

decltype evaluating the wrong type from an expression list

while experimenting with the answer from This post, ended up with the following piece of code:

#include <iostream>
#include <typeinfo>
 
 namespace Test
 {
    struct MyPtr
    {
        double operator, (int Input)
        {
            std::cout << "Operator, called" << std::endl;
            return 1.0;
        }

        MyPtr operator* ()
        {
            std::cout << "operator* called" << std::endl;
            return *this ;
        }

        MyPtr operator++ ()
        {
            std::cout << "operator++ called" << std::endl;
            return *this;
        }

        MyPtr operator!= (const MyPtr& Other)
        {
            std::cout << "operator!= called" << std::endl;
            return *this;
        }
    };

    struct Foo
    {
        MyPtr Ptr;
    };

    MyPtr begin(Foo& t)
    {
        return t.Ptr;
    }

    MyPtr end(Foo& t)
    {
        return t.Ptr;
    }
 }
 
int main()
{
    std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
                                 *begin(std::declval<Test::Foo&>()), 
                                  std::true_type{})).name() <<std::endl;
}

which yields:

d

Here, d comes from the comma operator. However, as the last expression inside the decltype specifier is std::true_type{}, why does the decltype specifier resolves to the type returned by the comma operator instead of std::true type.

My Theory is that std::true_type can be implicitly cast into an int, which operator,() here takes as a parameter, hence the decltype expression is equivalent to:

    std::cout << typeid(decltype(++begin(std::declval<Test::Foo&>()),
                                 declval<double&>())).name() <<std::endl;

Can you confirm this is correct?

What i am planning on doing when i will have a better grasp of the compiler's behavior, i plan on replacing the contents of the decltype specifier with:

    std::cout << typeid(decltype(void(++begin(std::declval<Test::Foo&>())),
                                 void(*begin(std::declval<Test::Foo&>())), 
                                  std::true_type{})).name() <<std::endl;

which will prevent operator,() from matching, even if it is overridden. Can you also confirm this is correct?

lundi 30 janvier 2023

HashTable:Determining Table size and which hash function to use

1)If the input data entries are around 10 raised to power of 9, do we keep the size of the hash table the same as input size or reduce the size? how to decide the table size? 2) if we are using numbers in the range of 10 raised to power of 6 as the key, how do we hash these numbers to smaller values? I know we use the modulo operator but module with what?

Kindly explain how these two things work. Its getting quite confusing. Thanks!!

I tried to make the table size around 75% of the input data size, that you can call as X. Then I did key%(X) to get the hash code. But I am not sure if this is correct.

Constructor with arguments having default value equivalent to default constructor? [duplicate]

Will it be correct to say that constructor with argument default values equivalent to default constructor ?

The below program :

#include <iostream>

using namespace std;

class X
{
    int i;
    char ch;

public:
    X()
    {
        cout << "<" << __PRETTY_FUNCTION__ << "> :" << this << endl;
    }

    X(int ii = 0) : i(ii)
    {
        cout << "<" << __PRETTY_FUNCTION__ << "> :" << this << ", i=" << i << endl;
    }

    ~X() { cout << "X::~X()" << endl; }
};

void f()
{
    static int i;

    static X x1(47);
    static X x2;

}

int main(int argc, char *argv[])
{
    f();

    return 0;
} ///:~

refuses to compile if int ii =0. i.e., default value is provided to ii

StaticObjectsInFunctions.cpp:30:14: error: call of overloaded ‘X()’ is ambiguous
   30 |     static X x2;
      |              ^~
StaticObjectsInFunctions.cpp:17:5: note: candidate: ‘X::X(int)’
   17 |     X(int ii = 0) : i(ii)
      |     ^

dimanche 29 janvier 2023

How to create a function that takes both function pointers and lambda as arguments?

I have the following class who has a method called errorHandler that needs to use several different callbacks:

class IOPin;
class IOPinHandler
{
    IOPinHandler();
    virtual ~IOPinHandler();

    static bool ptrFun(IOPinHandler&) { return true; };

    template<typename T>
    bool init(IOPin& obj, const T& param);

    template<typename HandlerReturn = void, typename ...Args>
    HandlerReturn errorHandler(const GpioStatusCode& code, HandlerReturn(*callback)(IOPinHandler& obj, const Args&...), const Args&... args);

    // Added this overload to support passing lambdas as arguments, 
    // however does not seems to be called
    template<typename HandlerReturn = void, typename ...Args>
    HandlerReturn errorHandler(const GpioStatusCode& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);
};

I can use the following:

return errorHandler(GpioStatusCode::wrongArgumentsError, &IOPinHandler::ptrFun);

And the code compiles successfully and runs as I expect it to do.


I can also use pass a lambda function in the following way:

auto fix = [](IOPinHandler& obj) -> bool 
{
    return true; 
};
return errorHandler(GpioStatusCode::wrongArgumentsError, static_cast<bool(*)(IOPinHandler&)>(fix));

This way, the code also compiles and runs successfully.


However, if I add capture to the lambda function, the code won't compile:

auto fix = [&](IOPinHandler& obj) -> bool 
{
    return true; 
};
return errorHandler(GpioStatusCode::wrongArgumentsError, fix);

I get the following compile time error:

error: no matching function for call to 'IOPinHandler::errorHandler(GpioStatusCode, IOPinHandler::init<GpioMode>::<lambda(IOPinHandler&)>&)'
   12 |         return errorHandler(GpioStatusCode::wrongArgumentsError, fix);

I thought that adding:

template<typename HandlerReturn = void, typename ...Args>
HandlerReturn errorHandler(const GpioStatusCode& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);

Would match the template instantiation for receiving the lambda function as argument, but the fact that I have to cast the lambda without capture and that the lambda with capture does not work either, kinda suggest to me that only the first definition or "errorHandler" is being invoked.

Is my reasoning right? How could I get pass this?


Edit: Full code.

#include <functional>

class IOPin;

class IOPinHandler
{

    public:
        template<typename ...T>
        IOPinHandler(const T&... args);
        virtual ~IOPinHandler(); 

        static bool ptrFun(IOPinHandler&);

        template<typename T>
        bool init(const T& param);

        template<typename HandlerReturn = void, typename ...Args>
        HandlerReturn errorHandler(const int& code, HandlerReturn(*callback)(IOPinHandler& obj, const Args&...), const Args&... args);

        // Added this overload to support passing lambdas as arguments, 
        // however does not seems to be called
        template<typename HandlerReturn = void, typename ...Args>
        HandlerReturn errorHandler(const int& code, const std::function<HandlerReturn(IOPinHandler&, const Args&...)>& callback, Args&... args);
};

template<typename ...T>
IOPinHandler::IOPinHandler(const T&... args)
{
    (init(args),...);
}

bool IOPinHandler::ptrFun(IOPinHandler&)
{
    return true;
}

template<typename T>
bool IOPinHandler::init(const T& param)
{
    // Compiles with no problem
    // return errorHandler(1, &IOPinHandler::ptrFun); 

    // Compiles with no problem
    // auto fix = [](IOPinHandler& obj) -> bool 
    // {
    //    return true; 
    // };
    // return errorHandler(1, static_cast<bool(*)(IOPinHandler&)>(fix));

    // Does not compiles
    auto fix = [&](IOPinHandler& obj) -> bool 
    {
        return true; 
    };
    return errorHandler(1, fix);    
}

int main(void)
{
    IOPinHandler a(1,'c',true);
    return 0;
}

'std::bad_weak_ptr' error while using shared_from_this

Note: Before posting the question, I have gone through the existing questions on std::bad_weak_error while using shared_from_this to pass the shared_ptr of the existing shared_ptr instance to another method. None of them are similar to this as:

  • There is already an existing shared_ptr instance of the class created before trying to call shared_from_this()
  • The class inherits from std::enable_shared_from_this<> publically.

Here is the sample code to reproduce the error:


#include <iostream>
#include <memory>

class ILogger {
public:
    virtual ~ILogger() {}

    virtual void Log() = 0;
};

class LogManager;

class Logger : public ILogger {
public:
    Logger(std::shared_ptr<LogManager> logManager)
        : m_logManager(logManager)
    {
    }

    void Log() override
    {
        std::cout << "Dump logs";
    }

private:
    std::shared_ptr<LogManager> m_logManager;
};

class ILogManager {
public:
    virtual ~ILogManager() {}

    virtual std::shared_ptr<ILogger> GetLogger() = 0;
};

class LogManager : public ILogManager, public std::enable_shared_from_this<LogManager> {
public:
    virtual std::shared_ptr<ILogger> GetLogger()
    {
        return std::static_pointer_cast<ILogger>(std::make_shared<Logger>(this->shared_from_this()));
    }
};

class LogManagerFactory {
public:
    static ILogManager* Create()
    {
        auto logManager = new LogManager();
        return logManager;
    }
};

int main()
{
    auto logManager = std::shared_ptr<ILogManager>(LogManagerFactory::Create());
    auto logger = logManager->GetLogger();
}

The error:

Program returned: 139
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr

Link to code: https://godbolt.org/z/GTcafM449

samedi 28 janvier 2023

Thread pool with job queue gets stuck

I want to split jobs among multiple std::thread workers and continue once they are all done. To do so, I implemented a thread pool class mainly based on this SO answer. I noticed, however, that my benchmarks can get stuck, running forever, without any errors thrown.

I wrote a minimal reproducing code, enclosed at the end. Based on terminal output, the issue seems to occur when the jobs are being queued. I checked videos (1, 2), documentation (3) and blog posts (4). I tried replacing the type of the locks, using atomics. I could not find the underlying cause.

Here is the snippet to replicate the issue. The program repeatedly counts the odd elements in the test vector.

#include <atomic>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

class Pool {
  public:
    const int worker_count;
    bool to_terminate = false;
    std::atomic<int> unfinished_tasks = 0;
    std::mutex mutex;
    std::condition_variable condition;
    std::vector<std::thread> threads;
    std::queue<std::function<void()>> jobs;

    void thread_loop()
    {
        while (true) {
            std::function<void()> job;
            {
                std::unique_lock<std::mutex> lock(mutex);
                condition.wait(lock, [&] { return (!jobs.empty()) || to_terminate; });

                if (to_terminate)
                    return;

                job = jobs.front();
                jobs.pop();
            }
            job();
            unfinished_tasks -= 1;
        }
    }

  public:
    Pool(int size) : worker_count(size)
    {
        if (size < 0)
            throw std::invalid_argument("Worker count needs to be a positive integer");

        for (int i = 0; i < worker_count; ++i)
            threads.push_back(std::thread(&Pool::thread_loop, this));
    };

    ~Pool()
    {
        {
            std::unique_lock lock(mutex);
            to_terminate = true;
        }
        condition.notify_all();
        for (auto &thread : threads)
            thread.join();
        threads.clear();
    };

    void queue_job(const std::function<void()> &job)
    {
        {
            std::unique_lock<std::mutex> lock(mutex);
            jobs.push(job);
            unfinished_tasks += 1;
            // std::cout << unfinished_tasks;
        }
        condition.notify_one();
    }

    void wait()
    {
        while (unfinished_tasks) {
            ; // spinlock
        };
    }
};

int main()
{
    constexpr int worker_count = 8;
    constexpr int vector_size = 1 << 10;
    Pool pool = Pool(worker_count);

    std::vector<int> test_vector;
    test_vector.reserve(vector_size);
    for (int i = 0; i < vector_size; ++i)
        test_vector.push_back(i);

    std::vector<int> worker_odd_counts(worker_count, 0);

    std::function<void(int)> worker_task = [&](int thread_id) {
        int chunk_size = vector_size / (worker_count) + 1;
        int my_start = thread_id * chunk_size;
        int my_end = std::min(my_start + chunk_size, vector_size);

        int local_odd_count = 0;
        for (int ii = my_start; ii < my_end; ++ii)
            if (test_vector[ii] % 2 != 0)
                ++local_odd_count;

        worker_odd_counts[thread_id] = local_odd_count;
    };

    for (int iteration = 0;; ++iteration) {
        std::cout << "Jobs.." << std::flush;
        for (int i = 0; i < worker_count; ++i)
            pool.queue_job([&worker_task, i] { worker_task(i); });
        std::cout << "..queued. " << std::flush;

        pool.wait();

        int odd_count = 0;
        for (auto elem : worker_odd_counts)
            odd_count += elem;

        std::cout << "Iter:" << iteration << ". Odd:" << odd_count << '\n';
    }
}

Here is the terminal output of one specific run:

[...]
Jobs....queued. Iter:2994. Odd:512
Jobs....queued. Iter:2995. Odd:512
Jobs..

C++ local static std::vector with initial value undefined behavior

In my project, part of code behavior like undefined behavior. It have correctly worked been awhile(six months), our team and test engineers doesn't reported any bug until a few day ago. A few day ago when i was making some test, the code run weird, after some debug step we found a function that behave unexpected. Also i run the same code different machine but we didn't observe anomaly.

enum class eQtnIfacePort : uint16_t {
    ETH1_1 = 0x0,
    WIFI0_0 = 0x2,
    L_HOST = 0x3,
    ETH1_0 = 0x8,
    WIFI2_0 = 0xb,
    DROP = 0x1f,
};

bool check_msg(eQtnIfacePort msg) {

    static std::vector<eQtnIfacePort> v{eQtnIfacePort::ETH1_1, eQtnIfacePort::WIFI0_0};

    for(auto &i : v) {
        std::cout << "vector item: " << static_cast<int>(i) << "\n";
        if (msg == i)
            return true;
    }

    return false;
}

Debug output of the above code only be "vector item: 0" or "vector item: 2", but i saw random numbers like 3451, 2348 which are not defined in eQtnIfacePort enum.

What am i doing wrong, is there compiler bug or missing c++ knowledge?

compiler option Os, -std=c++11 compiler version gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0 tested machine ubuntu 20.04

Please don't suggest like use const static std::array or anything else. I wonder cause of problem.

c++ list is getting empty after adding into another list

Im writing a genetic algorithm in c++ as a first project for my programming course at uni. I had almost everything done but a problem appeared. When I'm reading my input file with first four individuals im trying to load every one into a list, and then I want to load it into a list of whole population but that's where the problem begins - my individual, which is properly written from file is being added into a population, but it appears as an empty list inside a population.

void read(ifstream& input, list<list<int>>& population) {
    string line; //line is a variable that saves an individual that is currently being added
    string chromosom;
    list<int> individual;
    while(getline(input, line)){
        individual.clear();
        chromosom = "";
        for (auto znak : line)     //loop that is getting rid out of space character 
        {
            if (int(znak) != int(' '))
            {
                chromosom += znak;
            }
            else
            {
                int liczba = atoi(chromosom.c_str()); 
                individual.push_back(liczba);
                chromosom = ""; 
            }
        }
        int liczba = atoi(chromosom.c_str());
        individual.push_back(liczba);                           
        population.push_back(individual);
    }

    input.close();
}

I ve tried to another ways to do that but every time i had the same results, I even tried to copy my colleagues code but still no change. Do you guys have any idea about why this error appears and how to solve it?

jeudi 26 janvier 2023

unary '++': List

i implemented a custom List including an iterator using the example from a textbook, but when i try to iterate over the list using the iterator, i get the error:

Error C2675 unary '++': 'List::iterator' does not define this operator or a conversion to a type acceptable to the predefined operator

does anyone know what's wrong with my class? i'm pretty sure i copied it verbatim from the textbook. thanks!

/*
    list class itself - contains links to both ends, size, and many other methods
    concrete implementation of List ADT. different from vector because it allows
    us to add to middle of list in O(1) time, but does not support O(1) indexing[]
*/ 
template <typename Object>
class List {

private: 
    /*
        private nested Node class. contains data and pointers to prev/next
        along with appropriate constructor methods
        struct is a relic from C, essentially a class where members default to public
        used to signify a type that contains mostly data to be accessed directly rather
        than through methods
        Node is private, so only List will be able to access it's fields/methods
    */
    struct Node {
        Object data;
        Node* prev;
        Node* next;
        Node(const Object& d = Object{}, Node* p = nullptr, Node* n = nullptr) :
            data{ d }, prev{ p }, next{ n } {}
        Node(Object&& d, Node* p = nullptr, Node* n = nullptr) :
            data{ std::move(d) }, prev{ p }, next{ n }
     {}
    };

public:
    /*
        const_iterator class. abstracts notion of position, public nested class
        const_iterator stores pointer to current node and provides implementation of
        basic iterator operations, all in form of overloaded operators like =, ==, !=, ++     
    */
    class const_iterator {
    public:
        const_iterator():current{nullptr}{}
        
        const Object& operator*()const
        {
            return retrieve();
        }
        const_iterator& operator++()
        {
            current = current->next;
            return *this;
        }
        const_iterator operator++(int)
        {
            const_iterator old = *this;
            ++(*this);
            return old;
        }
        /*
        public methods of const_iterator all use operator overloading. operator==,
        operator!=, operator* are straightforward. separate routines are necessary for
        prefix and postfix versions of operator++ due to their different semantics. we 
        distinguish between them by their method signatures (empty parameter for prefix,
        int parameter for postfix). int is only used to distinguish between them. 
        in many cases where there is a choice between using prefix or postfix, prefix
        version is faster.
        
        */
        bool operator==(const const_iterator& rhs)const
        {
            return current == rhs.current;
        }
        bool operator!=(const const_iterator& rhs)const
        {
            return !(*this == rhs); 
        }

        /*
        protected allows classes that inherit from const_iterator to access these fields
        but not other classes
        */
    protected:
        Node* current;

        Object& retrieve()const
        {
            return current->data;
        }
        const_iterator(Node* p) : current{ p }
        {
        }
        /*
        the friend declaration is needed to grant the List class access to const_iterators
            nonpublic members
        */
        friend class List<Object>;
    };
    /*
        iterator class. abstracts notion of position. public nested class
        same functionality as const_iterator, except operator* returns a reference
        to the item being viewed, rather than a const reference
        iterator can be used in any routine that requires a const_iterator, but not
        vice-versa (in other words, iterator IS A const_iterator)
        
        iterator inherits from const_iterator, meaning it inherits all the data and 
        methods from const_iterator. it can then add new methods and override existing
        methods. here we are not adding any new data or changing the behavior of exising
        methods. we do add some new methods (with similar signatures to const_iterator)
     */
    class iterator : public const_iterator 
        //inheritance: iterator has same functionality as const_iterator
        //iterator can be used wherever const_iterator is needed
    {
    public:
        iterator() {}

        /*
         do not have to re-implement operator == and operator != (inherited unchanged)
         provide a new pair of operator++ implementations that override the original
         implementations from const_iterator. 
         provide an accessor/mutator pair for operator*. 
        
        */
        Object& operator*()
        {
            return const_iterator::retrieve();
        }
        const Object& operator*()const
        {
            return const_iterator::operator*();
        }
        iterator& operator++(int)
        {
            iterator old = *this;
            ++(*this);
            return old;
        }
    protected:
        /*
        protected constructor uses an initialization list to initialize the inherited
        current node.
        */
        iterator(Node* p) :const_iterator{ p } {}
        friend class List<Object>;
    };

public:
    /*
        constructor and big 5. because zero-parameter constructor and copy constructor
        must both allocate the header and tail nodes, we provide a init routine.
        init creates an empty list.
        the destructor reclaims the header and tail nodes, all other nodes, all other 
        nodes are reclaimed when the destructor invokes clear. similarly, the 
        copy-constructor is implemented by invoking public methods rather than attempting
        low-level pointer manipulations. 
    */
    List()
    {
        init();
    } 
    /*
     sentinel nodes - makes sense to create an extra node at each end of list to
     represent start/end markers. also referred to as header and tail nodes
     advantage of sentinel nodes is that it simplifies code by removing special cases
     example: without sentinels, removing the first node becomes a special case
     because we must reset the list's link to the first node during the remove
     operation, and because the remove algorithm in general needs to access the node
     prior to the node being removed (and without header, first node does not have
     prior)

    */
    void init()
    {
        theSize = 0;
        head = new Node;
        tail = new Node;
        head->next = tail;
        tail->prev = head;
    }

    ~List()
    {
        clear();
        delete head;
        delete tail;
    }

    // clear works by repeatedly removing items until the List is empty (uses pop-front)
    void clear()
    {
        while (!empty())
            pop_front();
    }


    List(const List& rhs)
    {
        init();
        for (auto& x : rhs)
        {
            push_back(x);
        }
    }
    List& operator=(const List& rhs)
    {
        List copy = rhs;
        std::swap(*this, copy);
        return *this;
    }
    List(List&& rhs)
        :theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail }
    {
        rhs.theSize = 0;
        rhs.head = nullptr;
        rhs.tail = nullptr;
    }
    List& operator=(List&& rhs)
    {
        std::swap(theSize, rhs.theSize);
        std::swap(head, rhs.head);
        std::swap(tail, rhs.tail);
        return *this;
    }

    // these methods return iterators
    iterator begin()
    {
        return { head->next };
    }
    const_iterator begin()const
    {
        return{ head->next };
    }
    iterator end()
    {
        return { tail };
    }
    const_iterator end()const
    {
        return{ tail };
    }
    int size()const
    {
        return theSize;
    }
    bool empty()const
    {
        return size() == 0;
    }


    Object& front()
    {
        return *begin();
    }
    const Object& front()const
    {
        return *begin();
    }
    Object& back()
    {
        return *--end();
    }
    const Object& back() const
    {
        return *--end();
    }
    
    /*
    cleverly obtain and use appropriate iterator
    insert inserts prior to a position, so push_back inserts prior to the endmarker
    pop_back line erase(-end()) creates a temporary iterator corresponding to the
    endmarker, retreats the temporary iterator, and uses that iterator to erase. 
    similar behavior occurs in back
    note also that we avoid dealing with node reclamation in pop_front and pop_back
    */
    void push_front(const Object& x)
    {
        insert(begin(), x);
    }
    void push_front(Object&& x)
    {
        insert(begin(), std::move(x));
    }
    void push_back(const Object& x)
    {
        insert(end(), x);
    }
    void push_back(Object&& x)
    {
        insert(end(), std::move(x));
    }
    void pop_front()
    {
        erase(begin());
    }
    void pop_back()
    {
        erase(--end());
    }

    /*
    inserting a new node between p and p->prev. works by getting a new node
    and then changing pointers of p and p-prev in the correct order
    also mention usefulness of the sentinels here.
    */
    iterator insert(iterator itr, const Object& x)
    {
        Node* p = itr.current;
        theSize++;
        Node* newNode = new Node{ x, p->prev,p };
        p->prev->next = newNode;
        p->prev = newNode;
        return newNode;
    }
    iterator insert(iterator itr, Object&& x)
    {
        Node* p = itr.current;
        theSize++;
        p->prev->next = new Node{ std::move(x), p->prev, p };
        p->prev = p->prev->next;
        return p->prev;
    }
    /*
    erase routines. frst version erases p by rearranging pointers of the nodes just 
    before and after p, and then returning an iterator representing the item after the
    erased element. like insert, erase must also update the size.
     
    second version of erase simply uses an iterator to call the first version of erase,
    note - cannot simply use itr++ in 'for' loop and ignore return iterator from erase,
    because the value of itr is stale immediately after the call to erase, which is why
    erase returns an iterator.
    */
    iterator erase(iterator itr)
    {
        Node* p = itr.current;
        iterator retVal{ p->next };
        p->prev->next = p->next;
        p->next->prev = p->prev;
        delete p;
        theSize--;

        return retVal;
    }
    iterator erase(iterator from, iterator to)
    {
        for (iterator itr = from; itr != to;)
        {
            itr = erase(itr);
        }
        return to;
    }

    /*
    data members for list - pointers to header and tail nodes. also keeps track of
    size in a data member so that the size method can be implemented in constant time
    */
    private:
        int theSize;
        Node* head;
        Node* tail;

    
};


int main()
{

    List<int> theList{};

    for (int i = 0; i < 10; i++)
        theList.push_back(i);

    List<int>::iterator iter = theList.begin();

    for(int i=0;i<5;i++)
        std::cout << *(iter++) << std::endl;


}

mercredi 25 janvier 2023

Why does std::array require the size as a template parameter and not as a constructor parameter?

There are many design issues I have found with this, particularly with passing std::array<> to functions. Basically, when you initialize std::array, it takes in two template parameters, <class T and size_t size>. However, when you create a function that requires and std::array, we do not know the size, so we need to create template parameters for the functions also.

template <size_t params_size> auto func(std::array<int, params_size> arr);

Why couldn't std::array take in the size at the constructor instead? (i.e.):

auto array = std::array<int>(10);

Then the functions would look less aggressive and would not require template params, as such:

auto func (std::array<int> arr);

I just want to know the design choice for std::array, and why it was designed this way.

This isn't a question due to a bug, but rather a question why std::array<> was designed in such a manner.

Invalid operands to binary expression [xcode c++]

Why do I have this error in my code?

void check_letter(string letter, string entry) {
    for(int i = 0; i < entry.length(); i++) {
        if(entry[i] == letter) {

        }
    }
}

Invalid operands to binary expression ('std::basic_string<char>::value_type' (aka 'char') and 'std::string' (aka 'basic_string<char, char_traits<char>, allocator<char>>'))`

I want to check each letter in the word, so I check all letters of the word in a loop. I tried it on a array char (I made the array with individual letters from the word) and I had the same error.

template parameter default value with dependancy to deduced template parameters

I am aware this question is quite similar to This post, however the cited post was about class template argument deduction. Here my question is about function template argument deduction.

I currently have the following piece of code, which enables users to specify the algorithm a method should use in order to compute some values. (Using a strategy Pattern is not applicable in this case for various reasons which are not relevant here)

#include <iostream>
#include <typeinfo>
template<typename T>
class BasicStrategy
{
    public:
    BasicStrategy(T& i_Input)
    {
        std::cout << "Applying Basic Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};

template<typename T>
class ComplexStrategy
{
    public:
    ComplexStrategy(T& i_Input)
    {
        std::cout << "Applying Complex Strategy to type : " << typeid(T).name() << " With value : " << i_Input <<std::endl;
    }
};

template<typename T, typename STRATEGY = BasicStrategy<T>>
void Func(T& i_Input)
{
    STRATEGY MyStrategy(i_Input);
}


int main()
{
    int i = 12;
    double d = 24;
    
    Func(i);
    Func(d);

    Func<int, ComplexStrategy<int>>(i);
    Func<double, ComplexStrategy<double>>(d);
    return 0;
}

I would like to know if it would be possible to simplify the interface of "Func()" in order to exempt the user from specifying redundant types if not using the "BasicStrategy" For instance, the "ideal" interface would look like this (i realize this is not possible though):

int main()
{
    int i = 12;
    double d = 24;

    Func(i);
    Func(d);

    Func<ComplexStrategy>(i);
    Func<ComplexStrategy>(d);
    return 0;
}

Of course, i could declare Func() like this

template<typename STRATEGY, typename T>
void Func(T& i_Input)

Which would not require the user to specify the type T twice, however, this prevents me from assigning a default strategy to the method, which would break a lot of existing code and making it less readable overall.

Is there a clean solution to this problem or is this a choice i have to make between the two options?

While loop in File Handling C++ [duplicate]

#include<iostream>
#include<fstream>
using namespace std;

int main() {

    ofstream f_out;
    f_out.open("file.txt");
    f_out<<"Hello!";
    f_out.close();

    ifstream f_in;
    f_in.open("file.txt");
   
    char ch;

    while(!f_in.eof()) {

        cout<<ch;
        f_in>>ch;
    }
    
    f_in.close();

    return 0;
}
while(!f_in.eof()) {

        cout<<ch;
        f_in>>ch;
    }

I have a problem in the above while loop specifically.

In the above code, inside the while loop why is cout statement before f_in statement. Usually, the cin statement comes before cout, but here its the other way round. If i write f_in first then cout then the program gives wrong o/p as Hello!!, instead of Hello!. Can anyone explain it to me in simple language why the above code is correct & my line of thought is incorrect. Thanks in advance. I am new to learning C++

mardi 24 janvier 2023

why is my rudimentary implementation of Vector faster than the stl version for push_back?

I have implemented a rudimentary vector using the code from the Weiss C++ textbook on data structures (see below). when i time it with 100,000 push_backs it takes 0.001 seconds.

when i do the exact same experiment using the stl::vector, it takes 0.008 seconds (roughly 8x slower). does anyone know why this is? thanks

#include <iostream>
#include <algorithm>
#include <ctime>
#include <vector>

template<typename Object>
class Vector {

public:

    // normal constructor
    explicit Vector(int initialSize = 0) :
        theSize{ initialSize }, theCapacity{ initialSize + SPARE_CAPACITY },
        objects{ new Object[theCapacity] }
    {}

    // copy constructor
    Vector(const Vector& rhs) :
        theSize{ rhs.theSize }, theCapacity{ rhs.theCapacity }, objects{ nullptr }
    {
        objects = new Object[theCapacity];
        for (int k = 0; k < theSize; ++k)
            objects[k] = rhs.objects[k];
    }

    // copy assignment operator
    Vector& operator=(const Vector& rhs)
    {
        Vector copy = rhs;
        std::swap(*this, copy);
        return *this;
    }

    // destructor
    ~Vector()
    {
        delete[] objects;
    }

    // move constructor
    Vector(Vector&& rhs) :
        theSize{ rhs.theSize }, theCapacity{ rhs.theCapacity }, objects{ rhs.objects }
    {
        rhs.objects = nullptr;
        rhs.theSize = 0;
        rhs.theCapacity = 0;
    }

    // move assignment operator
    Vector& operator=(Vector&& rhs)
    {
        std::swap(theSize, rhs.theSize);
        std::swap(theCapacity, rhs.theCapacity);
        std::swap(objects, rhs.objects);

        return *this;
    }

    void resize(int newSize)
    {
        if (newSize > theCapacity)
            reserve(newSize * 2); // talk about amortized time (python book)
        theSize = newSize;
    }

    void reserve(int newCapacity)
    {
        if (newCapacity < theSize)
            return;

        Object* newArray = new Object[newCapacity];
        for (int k = 0; k < theSize; ++k)
            newArray[k] = std::move(objects[k]);

        theCapacity = newCapacity;
        std::swap(objects, newArray);
        delete[] newArray;
    }

    Object& operator[](int index)
    {
        return objects[index];
    }

    const Object& operator[](int index)const
    {
        return objects[index];
    }

    bool empty() const
    {
        return size() == 0;
    }

    int size() const
    {
        return theSize;
    }

    int capacity() const
    {
        return theCapacity; 
    }

    void push_back(const Object& x)
    {
        if (theSize == theCapacity)
            reserve(2 * theCapacity + 1);

        objects[theSize++] = x; 
    }

    void push_back(Object&& x)
    {
        if (theSize == theCapacity)
            reserve(2 * theCapacity + 1);

        objects[theSize++] = std::move(x); 
    }

    void pop_back()
    {
        --theSize;
    }

    const Object& back() const
    {
        return objects[theSize - 1];
    }

    // iterator
    typedef Object* iterator;
    typedef const Object* const_iterator;

    iterator begin()
    {
        return &objects[0];
    }
    const_iterator begin() const
    {
        return &objects[0];
    }
    iterator end()
    {
        return &objects[size()];
    }
    const_iterator end() const
    {
        return &objects[size()];
    }

    static const int SPARE_CAPACITY = 16; 

private:
    int theSize;
    int theCapacity;
    Object* objects; 
};


int main()
{
    std::clock_t start;
    start = std::clock(); 
    std::vector<int> vec2{ 0 };
    for (int i = 0; i < 100000; i++)
        vec2.push_back(i);
    double duration = (std::clock() - start) / (double)CLOCKS_PER_SEC;

    std::cout << "printf: " << duration << '\n';


    start = std::clock();       
    Vector<int> vec{ 0 };
    for (int i = 0; i < 100000; i++)
        vec.push_back(i);

    duration = (std::clock() - start) / (double)CLOCKS_PER_SEC;

    std::cout << "printf: " << duration << '\n';


    
    
}

Unordered map where key is a pair

I have an unordered map where my key is a pair of <int, const Foo*> and value is a vector. I do not see any compilation or runtime error during insertion or lookup but I am not sure if this is most efficient code. Will the compiler create an efficient hash function for computing hash value of the key or should I use boost::hash?


`class Foo {
  public:
   Foo():var1(0){};
   ~Foo();
   void func(int a) {
      var1 = a;
   }
   int var1;
}

int main()
{
    Foo f1;
    f1.func(10);
    const Foo* fp = &f1;
    std::unordered_map<std::pair<uint,const Foo*>,std::vector<uint>> umap1;
    umap1[std::make_pair(1,fp)].emplace_back(100);
}
 `

Need to display the Student's name with their scores, average scores, and letter grade using arrays (needs to be in C++)

#include<iostream>
 #include<fstream>
 #include<string>
 #include<iomanip>
 using namespace std;


 const int MAX = 50;

 void GetData(ifstream& infile,string name[],int scores[][5],int& n)
 {
    n = 0;
    int i=0;
    int j=0;
     while (infile >> name[i]) {
        for (int j = 0; j < 5; j++)
            infile >> scores[i][j];
        i++;
     }
     n=i;
 }

 char determineGrade  (double avg)
 {
     
 if(avg>=90 && avg<=100)
 return 'A';
 else if(avg>=80 && avg<=89)
 return 'B';
 if(avg>=70 && avg<=79)
 return 'C';
 if(avg>=60 && avg<=69)
 return 'D';
 if(avg>=50 && avg<=59)
 return 'F';
 }


 void Average(int a[][5],char grade[],double avg[],int no_of_students)
 {
    for(int i=0; i<no_of_students; i++)
    {
    double sum =0;
        for(int j=0; j<5; j++)
        sum+= a[i][j];
    avg[i] = sum/static_cast<double> (5);
    grade[i] = determineGrade(avg[i]);
    }
 }

 
 void PrintResults(string name[],double avg[],int scores[][5],char grade[],int n)
 {
 for(int i=0; i<n; i++){
 cout << left << setw(10)<< name[i];
    for(int k=0; k<5; k++)
        cout << right << setw(8) << scores[i][k];
    cout << endl;
 }
 cout << setw(8) <<"Average ";
 for(int i=0; i<n; i++)
     cout << setw(5) << avg[i];
     cout << endl;
    
    
 }

 int main()
 {

 string name[MAX];
 
 int scores[MAX][5];
 
 char grade[MAX];
 int no_of_students;
 double avg[MAX];

 ifstream infile("StudentData.txt");

 if(!infile)
 {
    cout <<"unable to open file.so exiting from program" << endl;
    return 0;
 }

 GetData(infile, name, scores, no_of_students);
 infile.close();
 Average(scores, grade, avg, no_of_students);
 PrintResults(name,avg,scores,grade,no_of_students);


 return 0;
 }

I tried messing around with the determineGrade but it seems to not work, and I also change the while loop to see if that was the problem but it was not. I believe I am missing an outfile. I also believe that the arrays are incorrect but it does not give me an error; it just gives me the cout that I put whenever the file will not open.

Error when I attempt to split a string into individual characters

I read online you can "separate" a string and well it doesn't work. Of course the code is more complex than this but I only have troubles in this part.As I said below as well, the exact error is:

no viable conversion from 'std::__ndk1::basic_string<char, std::__ndk1::char_traits, std::__ndk1::allocator >::value_type' (aka 'char') to 'std::__ndk1::string' (aka 'basic_string<char, char_traits, allocator >')

So I have no idea how to proceed, but my code is as follows:

#include<iostream>

using namespace std;

int main()

{

string word;

cin>>word;

string word1 = word [0];

string word2 = word[1];

string word3 = word[2];

string word4 = word[3];

return 0;

}

The exact error I get is:

no viable conversion from 'std::__ndk1::basic_string<char, std::__ndk1::char_traits, std::__ndk1::allocator >::value_type' (aka 'char') to 'std::__ndk1::string' (aka 'basic_string<char, char_traits, allocator >')

lundi 23 janvier 2023

thread_local shared_ptr object is causing sigsegv when destructing

I have a program, which is using thread_local std::shared_ptr to manage some objects that are mainly accessed thread-locally. However when the thread is joined and the thread local shared_ptr is destructing, there is always SIGSEGV when debugging if the program is compiled by MinGW (Windows 10). Here is a minimum code to reproduce the bug:

// main.cpp
#include <memory>
#include <thread>

void f() {
    thread_local std::shared_ptr<int> ptr = std::make_shared<int>(0);
}

int main() {
    std::thread th(f);
    th.join();
    return 0;
}

How to compile:

g++ main.cpp -o build\main.exe -std=c++17

Compiler version:

>g++ --version
g++ (x86_64-posix-seh-rev2, Built by MinGW-W64 project) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Run using gdb it will give SIGSEGV in new thread, when the main thread is waiting for join(). It works fine when compiled by gcc, clang (Linux) and MSVC (Windows).

I tried to debug and found that, a continuous segment of memory containing the thread local shared_ptr was erased to repeated 0xfeeefeee before destruction when calling RtlpWow64SetContextOnAmd64. The frames:

RtlpWow64SetContextOnAmd64 0x00007ffd8f4deb5f
RtlpWow64SetContextOnAmd64 0x00007ffd8f4de978
SbSelectProcedure 0x00007ffd8f4ae2e0
CloseHandle 0x00007ffd8ce3655b
pthread_create_wrapper 0x00007ffd73934bac
_beginthreadex 0x00007ffd8e9baf5a
_endthreadex 0x00007ffd8e9bb02c
BaseThreadInitThunk 0x00007ffd8ec87614
RtlUserThreadStart 0x00007ffd8f4c26a1

The assembly:

...
mov    %rax,(%rdi)
movdqu %xmm0,(%rsi)               ; <------ erased here
call   0x7ffd8f491920             ; <ntdll!RtlReleaseSRWLockShared>
mov    $0x1,%r9d
mov    0x30(%rsp),%rbx
...

later the shared_ptr is destructed, and when reading 0xfeeefeee there is SIGSEGV.

I want to know that:

  • Why MinGW (or Windows library?) is erasing the thread local storage before destruction? In my opinion erasing memory should only happen after the destruction. I notice that if join() is replaced by detach(), the program exits normally. Maybe join() did something to instruct the new thread to erase the storage?
  • Is such behavior a violation of standard? I think the standard should forbid erasing the memory before destruction. Please correct me if I'm mistaken.

dimanche 22 janvier 2023

c++ initialize vector with pointers to class template

i try to init std vector with pointer to tamplate class
using c++11 and g++
Like this and it fail:

template <typename T>
struct Column  
{
    Column( T data)
    {             
        this->data = data;
    }

    T data;
    
}; 

int main(int argv,char** argc)
{
  std::vector<std::vector<Column*>> csv;
  
}

This i need to i can init Column with diffrent types like this :

 Column<std::string>* tmpString = new Column<std::string>(each);
 csv[0].push_back(tmpString);    

or 

 Column<int>* tmpInt = new Column<int>(each);
 csv[0].push_back(tmpString); 

is there any way to do this ? or maybe better way ?

samedi 21 janvier 2023

How to resolve warning related to deprecated armadillo function in C++

I an very new to C++ and I am using C++ library (armadillo) for my UG project. I was using computer in which armadillo was already installed. When I compiled the code it was warning free. Very recently I updated armadillo library with recent release (and forget to keep backup) and now my compiler showing following warning 485 13 D:\LAB HDD\main.cpp [Warning] 'arma::mat_injector<arma::Mat<eT> > arma::Mat<eT>::operator<<(eT) [with eT = double]' is deprecated [-Wdeprecated-declarations]

where the associated code is if(temp1==2) { uvec q1 = find(arma::strans(atmp)); q2<<M(q1(0))<<M(q1(1))<<endr; //there is warning EdgeU.insert_cols(n, arma::strans(q2)); q3<<m<<k;//there is warning Triangle.insert_cols(n,arma::strans(q3)); n=n+1; }

Is there anyone who can point out why it is showing warning at two instances? any reference where I can read about to remove these warning? Thank you.

I tried to go through the library which mentioning the exception. However, I am not expert therefore probably I am missing something.

I am expecting that the code will compile with minimul warnings and this issue may affect the future work.

vendredi 20 janvier 2023

create a child process in C++ (linux) [closed]

I'm very much a newbie to this kind of thing so please do try to explain any new terms that you use.

I have a main program. As part of it, what I would like to do is to run a shell program (in this case Stockfish15) in a separate shell. I then want to pass some commands to it in the code, and then read the output and use it in the rest of my main program.

I understand that to do this I need to create a child process and then redirect the input and output stream of it. But I don't know how to do that.

So, my question is, how do I create a child process and redirect its input/output on a ubuntu system (in C++11)?

I have found this resource. However, I didn't find it very helpful because a) it seems to be giving Windows specific instructions while I am on a Ubuntu system and b) it uses a bunch of functions in the code without explaining any of them.

Why does the IDE say that the function is supposedly not defined?

Can you tell me why the IDE indicates that the "func" function is not defined, although I have defined it below and the code is compiled without errors in principle? This happens only with the prototype of a function that returns a pointer to an array in this style. enter image description here

#include <iostream>

auto func(int value) -> int(*)[10]; // Function definition for "func" not found

int main()
{
  // some code

  return 0;
}

auto func(int value) -> int(*)[10]
{
  return nullptr;
}

There is no such indicator if you describe the prototype in the old style as int(*func(int value))[10]

also, everything is normal if you write like this:

#include <iostream>

using arr_ptr = int(*)[10];

auto func(int value) -> arr_ptr;

int main()
{
  // some code

  return 0;
}

auto func(int value) -> arr_ptr
{
  return nullptr;
}

I am writing a number in Visual Studio 2022. 20 standard is specified in the settings

The code compiles but I expect there won't be any error indicators...

What is the meaning of : in a c++ constructor? [duplicate]

I have come across an example in ros2 using : for a class constructor:

class MinimalPublisher : public rclcpp::Node
{
  public:
    MinimalPublisher()
    : Node("minimal_publisher"), count_(0)
    {
       publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
       timer_ = this->create_wall_timer(
       500ms, std::bind(&MinimalPublisher::timer_callback, this));
    }

https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html

here in the above lines -- why is MinimalPublisher() : Node("minimal_publisher"), count_(0) declared like this and not inside the constructor? i can refer from this question What is this weird colon-member (" : ") syntax in the constructor? that it is called member Initializer list. but my question is here, there are some values written directly has member Initializer list and some as individual lines. what calls for this difference as the function needs to be called anyway as there are other instructions in the function?

i tried to search the significance of :and i found this member Initializer list What is this weird colon-member (" : ") syntax in the constructor? but i didnt get y its used here in this senario.

jeudi 19 janvier 2023

first friend function template declaration is visible through `using namespace` but not through qualified name lookup [duplicate]

I have the following code I compile with C++11. This code is a simplification of a real world usage.

namespace bar {
template<int M = 10>
struct S {
    template<int N = M*2>
    friend int foo(S) { 
        return N-M; 
    }
};

template<int M, int N>
int foo(S<M>);

} /* end of bar */

int main() {
    bar::S<> s;
    /* OK    { using namespace bar; return foo<42>(s) + foo<>(s); } // */
    /* NOK   { return foo<42>(s) + foo<>(s); } // */
    /* NOK   { using namespace bar; return bar::foo<42>(s) + bar::foo<>(s); } // */
    /* NOK */{ return bar::foo<42>(s) + bar::foo<>(s); } // */
}

My question is: Why does it compile with using namespace bar; with unqualified name lookup (see line with /* OK )? While it does not compile in the variant using qualified name lookup (bar::foo<>()) or unqualified name lookup without using namespace (see lines with /* NOK )?

Find numbers with fixed length and fixed sum of digits

I have to solve the problem of finding the number of numbers having a length(i.e, number of digits) L(given as input) and sum of digits S(given also as input).

Well,my approach is to make L nested loops, each starting from i = 0(except the first loop which starts from i =1) to i = 9, and check if the sum of the iterators(wich represent the digits) of the loops is equal to S,and if so increment the counter by 1.

But since L is variable, i don't understand how to make L loops.
I read this post, but I still don't get how to write the code.
Any hint please?

mercredi 18 janvier 2023

Is it a race condition to start a thread in a constructor [closed]

I've heard arguments both for and against starting background threads in the constructor of classes. The camp that seems to be for it argues that RAII implies we should do all our initialization in a constructor. But I have heard others claim that starting a thread in a constructor is a race condition as the vtable may be mutated if the class is a base class for a derived type. This would mean the thread may start running and calling virtual functions that are in an undefined state at this point. Is this correct? Essentially this boils down to if it's safe to spin up a new thread in a class constructor, or if I need to utilize a Start() function even for classes where I would want a background thread to exist for the class lifetime so the stack can manage it's lifetime and join synchronization behavior.

How to properly declare a list in a class

Context: I'm at the second year of Uni and we started using classes and understanding of creating some little applications. I'm building an employer class, every employer has 4 parameters: serial_number, name, surname, earnings and then there also junior and senior employers, with all the above but other parameters too. For example junior employers have a set of skills and intern: first one is a list of skills that a junior can have and the second is at which senior employer they are assigned. ex. Junior with serial_number3 is the intern of Senior with serial_number1

NOW: I make use of the employer.h for the easy stuff, but when I get into declaring the list skills I just didn't understand what I should do.

#ifndef JUNIOR_H
#define JUNIOR_H

#include "employer.h"

#include <list>
using namespace std;

class junior : public employer
{
public:
    junior(string serial, string name, string surname, double earns, list<string> sk, string in)
        : employer(serial, name, surname, earns), skills(sk), intern(in) {}

    list<string> getSkills() const { return skills; }
    string getIntern() const { return intern; }

private:
    list<string> skills;
    string intern;

};

#endif // JUNIOR_H

Could I simply put in the body of the constructor this?

{ skills.push_back(sk); }

mardi 17 janvier 2023

Static member function and thread safety

I've a private static method in a class that has all the methods as static. It's a helper class that helps with logging and other stuff. This helper class would be called by multiple threads. I don't understand how the method in question is working safely with multiple threads without a lock.

//Helper.cpp


std::recursive_mutex Logger::logMutex_;


void Logger::write(const std::string &logFilePath, const std::string &formattedLog)
{
    std::lock_guard<std::mutex> guard(logMutex_);
    std::ofstream logFile(logFilePath.c_str(), std::ios::out | std::ios::app);

    if (logFile.is_open())
    {
        logFile << formattedLog;
        logFile.close();
    }
}

void Logger::error(const string &appId, const std::string &fmt, ...)
{
    auto logFile = validateLogFile(appId); //Also a private static method that validates if a file exists for this app ID.
    if (!logFile.empty())
    {
        //Format the log

        write(logFile, log);
    }
}
//Helper.h


class Logger
{
    public:
        static void error(const std::string &Id, const std::string &fmt, ...);
    private:
        static void write(const std::string &fileName, const std::string &formattedLog);
        static std::recursive_mutex logMutex_;
};

I understand that the local variables inside the static methods are purely local. i.e., A stack is created every time these methods are called and the variables are initialized in them. Now, in the Logger::write method I'm opening a file and writing to it. So when multiple threads calls the write method through the Logger::error method(Which is again static) and when there's no lock, I believe I should see some data race/crash.
Because multiple threads are trying to open the same file. Even if the kernel allows to open a file multiple times, I must see some fault in the data written to the file.

I tested this with running up to 100 threads and I see no crash, all the data is being written to the file concurrently. I can't completely understand how this is working. With or without the lock, I see the data is being written to the file perfectly.

TEST_F(GivenALogger, WhenLoggerMethodsAreCalledFromMultipleThreads_AllTheLogsMustBeLogged)
{
    std::vector<std::thread> threads;
    int num_threads = 100;

    int i = 0;

    for (; i < num_threads / 2; i++)
    {
        threads.push_back(std::thread(&Logger::error, validId, "Trial %d", i));
    }

    for (; i < num_threads; i++)
    {
        threads.push_back(std::thread(&Logger::debug, validId, "Trial %d", i));
    }

    std::for_each(threads.begin(), threads.end(), [](std::thread &t) { t.join(); });

    auto actualLog = getActualLog(); // Returns a vector of log lines.
    EXPECT_EQ(num_threads, actualLog.size());
}

Also, how should I properly/safely access the file?

Output for C++ program is always -0 [duplicate]

I want to write a program that converts Fahrenheit into Celsius by function and running it through a for loop with i = 0, i <= 20, i++

I've made a function that converts Fahrenheit and celsius and put that in a for loop that goes through 0-20 with i being the argument for the function but the output of the loop is always -0

   #include <iostream>
   #include <cmath>
   using namespace std;
   double celsius(double f){
     return (5/9)*(f - 32);
   }
   int main() {
     cout << "Celsius Temperature Table\n\n";
     for(int i = 0; i <= 20; i++){
       double c = celsius(i);
       cout << i << "f is " << c << "c\n";
     }
     return 0;
   }

this=0x0 on the debugger

I'm trying to implement a memory manager that manages a block of memory that I allocated using the chained lists to preserve its state but I have some problems

#0 0x6fce11f4   libstdc++-6!_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev() (C:\Program Files\CodeBlocks\MinGW\bin\libstdc++-6.dll:??)
#1 0x401bac Programme::Programme(this=0x0) (C:\Users\hoste\Documents\Code Block\Gestionnaire_Memoire\Memoire.cpp:24)
#2 0x401f06 Memoire::ajoutProgramme(this=0x63fdbc, position=0, P=..., L=..., prog=0xca3d08) (C:\Users\hoste\Documents\Code Block\Gestionnaire_Memoire\Memoire.cpp:60)
#3 0x401712 main() (C:\Users\hoste\Documents\Code Block\Gestionnaire_Memoire\main.cpp:23)

Allocation of memory constructor of class programme

function whose call is problematic Calling of the function

debugging the program allows me to see that the P pointer is worth 0x0, but I don't know how to fix it

C++ how can I read runtime bitset parameter from file which I will use non-constexpr class

I have a problem and can not figure it out on my own. I am describing it and want you to give me ideas about it, please.

I need to define a bitset with dynamic size:

int x = fileparser.read("value"); // This fileparser is a custom class that reads .ini files.
std::bitset<x> myBitset;

but this bitset's size should be read from the file. So as you know, bitset can not handle runtime parameters cause of template arguments.

  • I wrote a file parser class but I can not convert it to constexpr because it is a singleton and should return a static instance in one of its methods.
  • I don't want to use the boost library.
  • Also C++11 has a defect in constexpr classes and I'm facing it (ref: https://stackoverflow.com/a/36489493/12347681)

So, how can I handle it? I want to read a value from the file and use it as a constexpr.

Thanks in advance.

EDIT: When I convert my reader class to constexpr, I am facing the above defect from C++11. Is there a way to use my file reader class to determine the size of the bitset?

ld returned 1 exit status in C++ [closed]

I am running this code for several hour but getting error "ld returned 1 exit status". Problem actually lye in function which are on the top nd switch which I have used at the end.

Actually it program which will preform a task of registration , login and forgot password.

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void login();
void registration();
void forgot();

int main(){
    
    int c;
    
    cout<<"\t\t\t___________________________________________________________\n\n\n";
    cout<<"\t\t\t                     WELCOME TO LOGIN PAGE                 \n\n";
    cout<<"\t\t\t___________________________ MENU ___________________________\n";
    cout<<"                                                                    \n\n";
    cout<<"\t\t\t | Press 1 to LOGIN                         |"<<endl;
    cout<<"\t\t\t | Press 2 to REGISTER                      |"<<endl;
    cout<<"\t\t\t | Press 2 to if you forgot your PASSWORD   |"<<endl;
    cout<<"\t\t\t | Press 4 to EXIT                          |"<<endl;
    
    cout<<"\n\t\t\t Please enter your choice: ";
    cin>>c;
    
    switch(c){
        case 1:
            login();
            break;
        case 2:
            registration();
            break;
        case 3:
            forgot();
            break;
        case 4:
            cout<<"Thank You!";
            break;
        default:
            cout<<"Invalid Input";
    }
    
    
    
    
}

lundi 16 janvier 2023

CPP Cross use methods in different CPP files throws "was not declared in this scope"

I have following files

  • main.cpp
  • common.h
  • A.cpp
  • A.h
  • B.cpp
  • B.h

Some pseudo code:

main.cpp:

#include "common.h"
#include "A.h"
#include "B.h"

void main(....) {
    funca1();
}

A.h:

#pragma once
funca1();
funca2();

B.h:

#pragma once
funcb1();
funcb2();

A.cpp:

#include "A.h"
#include "B.h"

void funca1() {
    funcb2();
}

void funca2() {
    // do stuff
}

B.cpp:

#include "A.h"
#include "B.h"

void funcb1() {
    funca2();
}

void funcb2() {
    // do stuff
}

Compiling this throws errors like

firmware\A.cpp:122:73: error: 'funcb2' was not declared in this scope

This is an arduino project I'm trying to convert from .ino files to generic CPP code to be comilable in platformio - and it's driving me crazy :/

dimanche 15 janvier 2023

What does "int*&&" do in C++?

I'm coming from a C# background and trying to learn a little C++. I came across the following lines:

int x[3] = { 1, 2, 3 };
int*&& y = x;
int* z = y;

I know what pointers and arrays are and have some small understanding on lvalue and rvalue references. However I can't wrap my head around what int*&& y = x; actually does. It would read like it creates a pointer to an rvalue reference, is this correct? What would be the use case of something like that, e.g. what is going on in memory if we execute this?

samedi 14 janvier 2023

Binary tree children not being stored into variable reference

So I'm creating this binary tree and here is what I've gotten to:

#include <cmath>
#include <random>
#include <queue>
 
 
const int MIN_CONTAINER_SIZE = 5;
 
 
struct Point {
    int x, y;
 
    inline bool operator==(const Point pnt) const {
        return x == pnt.x && y == pnt.y;
    }
 
    inline bool operator!=(const Point pnt) const {
        return x != pnt.x && y != pnt.y;
    }
 
    Point() = default;
 
    Point(int x_val, int y_val) {
        x = x_val;
        y = y_val;
    }
 
    inline std::pair<int, int> sum(Point &other) const {
        return std::make_pair(x + other.x, y + other.y);
    }
 
    inline std::pair<int, int> abs_diff(Point &other) const {
        return std::make_pair(abs(x - other.x), abs(y - other.y));
    }
};
 
 
struct Rect {
    Point top_left, bottom_right;
    Point center;
    int width, height;
 
    Rect() = default;
 
    Rect(Point top_left_val, Point bottom_right_val) {
        std::pair<int, int> sum = top_left_val.sum(bottom_right_val);
        std::pair<int, int> diff = top_left_val.abs_diff(bottom_right_val);
        top_left = top_left_val;
        bottom_right = bottom_right_val;
        center = Point((int) round(((double) sum.first) / 2.0), (int) round(((double) sum.second) / 2.0));
        width = diff.first;
        height = diff.second;
    }
};
 
 
struct Leaf {
    Rect container;
    Leaf *left, *right;
    Rect *room;
 
    Leaf(Rect container_val) {
        container = container_val;
        left = nullptr;
        right = nullptr;
        room = nullptr;
    }
 
    bool split(std::mt19937 &random_generator) {
        if (left && right) {
            return false;
        }
 
        std::uniform_int_distribution<> split_vertical_distribution(0, 1);
        bool split_vertical_val = split_vertical_distribution(random_generator);
        if ((container.width > container.height) && (((double) container.width / container.height) >= 1.25)) {
            split_vertical_val = true;
        } else if ((container.height > container.width) && (((double) container.height / container.width) >= 1.25)) {
            split_vertical_val = false;
        }
 
        int max_size = (split_vertical_val) ? container.width - MIN_CONTAINER_SIZE : container.height - MIN_CONTAINER_SIZE;
        if (max_size <= MIN_CONTAINER_SIZE) {
            return false;
        }
 
        std::uniform_int_distribution<> pos_distribution(MIN_CONTAINER_SIZE, max_size);
        int pos = pos_distribution(random_generator);
 
        if (split_vertical_val) {
            pos += container.top_left.x;
            left = new Leaf{
                Rect{
                    Point{
                        container.top_left.x, container.top_left.y
                    },
                    Point{
                        pos - 1, container.bottom_right.y,
                    }
                }
            };
            right = new Leaf{
                Rect{
                    Point{
                        pos + 1, container.top_left.y,
                    },
                    Point{
                        container.bottom_right.x, container.bottom_right.y
                    }
                }
            };
        } else {
            pos += container.top_left.y;
            left = new Leaf{
                Rect{
                    Point{
                        container.top_left.x, container.top_left.y
                    },
                    Point{
                        container.bottom_right.x, pos - 1,
                    }
                }
            };
            right = new Leaf{
                Rect{
                    Point{
                        container.top_left.x, pos + 1,
                    },
                    Point{
                        container.bottom_right.x, container.bottom_right.y
                    }
                }
            };
        }
 
        return true;
    }
};
 
void split_bsp(Leaf &bsp, std::mt19937 &random_generator, int split_iteration) {
    std::queue<Leaf> queue;
    queue.push(bsp);
    while (split_iteration > 0 && !queue.empty()) {
        Leaf current = queue.front();
        queue.pop();
 
        if (current.split(random_generator) && current.left && current.right) {
            queue.push(*current.left);
            queue.push(*current.right);
            split_iteration -= 1;
        }
    }
}
 
void create_map(unsigned int seed) {
    int grid_width = 50;
    int grid_height = 100;
    std::mt19937 random_generator(seed);
    Leaf bsp = Leaf{
        Rect{
            Point{0, 0},
            Point{grid_width - 1, grid_height - 1}
        }
    };
    split_bsp(bsp, random_generator, 5);
}
 
int main() {
    for (int i = 0; i < 1000; i++) {
        create_map(i);
    }
}

However, during the while loop in split_bsp, the binary tree is able to split and successfully creates and stores the children. But on the next iteration, it resets the current variable deleting any progress. The program should store the children onto the bsp parameter. How can I fix this?

vendredi 13 janvier 2023

Segmentation fault in C++ program which generates a 2D grid [duplicate]

So I've been trying to convert this Python module to a C++ module and I've finished the logic, however, I've encountered some segmentation faults. The module is meant to create a binary space partition to generate the rooms, then it will use a minimum spanning tree and the A* algorithm to draw the hallways.

The map.cpp file:

// Custom includes
#include "astar.h"
#include "bsp.h"

// External includes
#include <unordered_set>


// ----- STRUCTURES ------------------------------
struct LevelConstants {
    int level, width, height;
};


struct Edge {
    int cost;
    Rect source, destination;

    inline bool operator<(const Edge edg) const {
        // The priority_queue data structure gets the maximum priority, so we need to
        // override that functionality to get the minimum priority
        return cost > edg.cost;
    }

    inline bool operator==(const Edge edg) const {
        return cost == edg.cost && source == edg.source && destination == edg.destination;
    }
};

template<>
struct std::hash<Edge> {
    size_t operator()(const Edge &edg) const {
        size_t res = 0;
        hash_combine(res, edg.cost);
        hash_combine(res, edg.source);
        hash_combine(res, edg.destination);
        return res;
    }
};

// ----- FUNCTIONS ------------------------------
inline std::vector<Point> collect_positions(std::vector<std::vector<int>> *grid, TileType target) {
    // Iterate over grid and check each position
    std::vector<Point> result;
    for (int y = 0; y < grid->size(); y++) {
        for (int x = 0; x < grid[y].size(); x++) {
            if ((*grid)[y][x] == target) {
                result.push_back(Point{
                    x, y
                });
            }
        }
    }

    // Return result
    return result;
}

void
split_bsp(Leaf *bsp, std::vector<std::vector<int>> *grid, std::mt19937 *random_generator, int split_iteration) {
    // Start the splitting using a queue
    std::queue<Leaf> queue;
    queue.push(*bsp);
    while (split_iteration > 0 && !queue.empty()) {
        // Get the current leaf from the deque object
        Leaf current = queue.front();
        queue.pop();

        // Split the bsp if possible
        if (current.split(grid, random_generator, true) && current.left && current.right) {
            // Add the child leafs so they can be split
            queue.push(*current.left);
            queue.push(*current.right);

            // Decrement the split iteration
            split_iteration -= 1;
        }
    }
}

std::vector<Rect> generate_rooms(Leaf *bsp, std::vector<std::vector<int>> *grid, std::mt19937 *random_generator) {
    // Create the rooms
    std::vector<Rect> rooms;
    std::queue<Leaf> queue;
    queue.push(*bsp);
    while (!queue.empty()) {
        // Get the current leaf from the stack
        Leaf current = queue.front();
        queue.pop();

        // Check if a room already exists in this leaf
        if (current.room) {
            continue;
        }

        // Test if we can create a room in the current leaf
        if (current.left && current.right) {
            // Room creation not successful meaning there are child leafs so try again on the child
            // leafs
            queue.push(*current.left);
            queue.push(*current.right);
        } else {
            // Create a room in the current leaf and save the rect
            while (!current.create_room(grid, random_generator)) {
                // Width to height ratio is outside of range so try again
                continue;
            }

            // Add the created room to the rooms list
            rooms.push_back(*current.room);
        }
    }

    // Return all the created rooms
    return rooms;
}

std::unordered_set<Edge> create_connections(std::unordered_map<Rect, std::vector<Rect>> *complete_graph) {
    // Use Prim's algorithm to construct a minimum spanning tree from complete_graph
    Rect start = complete_graph->begin()->first;
    std::priority_queue<Edge> unexplored;
    std::unordered_set<Rect> visited;
    std::unordered_set<Edge> mst;
    unexplored.push(Edge{0, start, start});
    while (mst.size() < complete_graph->size() - 1) {
        // Get the neighbour with the lowest cost
        Edge lowest = unexplored.top();
        unexplored.pop();

        // Check if the neighbour is already visited or not
        if (visited.count(lowest.destination)) {
            continue;
        }

        // Neighbour isn't visited so mark it as visited and add its neighbours to the heap
        visited.insert(lowest.destination);
        for (Rect neighbour: complete_graph->at(lowest.destination)) {
            if (!visited.count(neighbour)) {
                unexplored.push(
                    Edge{
                        lowest.destination.get_distance_to(&neighbour),
                        lowest.destination,
                        neighbour,
                    }
                );
            }
        }

        // Add a new edge towards the lowest cost neighbour onto the mst
        if (lowest.source != lowest.destination) {
            // Save the connection
            mst.insert(lowest);
        }
    }

    // Return the constructed minimum spanning tree
    return mst;
}

void create_hallways(std::vector<std::vector<int>> *grid, std::mt19937 *random_generator,
                     std::unordered_set<Edge> *connections, int obstacle_count) {
    // Place random obstacles in the grid
    std::vector<Point> obstacle_positions = collect_positions(grid, TileType::Empty);
    for (int i = 0; i < obstacle_count; i++) {
        std::uniform_int_distribution<> obstacle_point_distribution(0, (int) obstacle_positions.size());
        int obstacle_point_index = obstacle_point_distribution(*random_generator);
        Point obstacle_point = obstacle_positions[obstacle_point_index];
        obstacle_positions.erase(obstacle_positions.begin() + obstacle_point_index);
        (*grid)[obstacle_point.y][obstacle_point.x] = TileType::Obstacle;
    }

    // Use the A* algorithm with to connect each pair of rooms making sure to avoid the obstacles
    // giving us natural looking hallways. Note that the width of the hallways will always be odd in
    // this implementation due to numpy indexing
    const int HALF_HALLWAY_SIZE = HALLWAY_SIZE / 2;
    for (Edge connection: *connections) {
        for (Point path_point: calculate_astar_path(grid, connection.source.center, connection.destination.center)) {
            // Place a rect box around the path_point using HALLWAY_SIZE to determine the width and
            // height
            Rect{
                Point{
                    path_point.x - HALF_HALLWAY_SIZE,
                    path_point.y - HALF_HALLWAY_SIZE,
                },
                Point{
                    path_point.x + HALF_HALLWAY_SIZE,
                    path_point.y + HALF_HALLWAY_SIZE,
                }
            }.place_rect(grid);
        }
    }
}

void place_tile(std::vector<std::vector<int>> *grid, std::mt19937 *random_generator, TileType target_tile,
                std::vector<Point> *possible_tiles) {
    // Get a random floor position and place the target tile
    std::uniform_int_distribution<> possible_tiles_distribution(0, (int) (*possible_tiles).size());
    int possible_tile_index = possible_tiles_distribution(*random_generator);
    Point possible_tile = possible_tiles->at(possible_tile_index);
    (*grid)[possible_tile.y][possible_tile.x] = target_tile;
}


std::pair<std::vector<std::vector<int>>, LevelConstants> create_map(int level, unsigned int seed) {
    // Initialise a few variables needed for the map generation
    int grid_width = MAP_GENERATION_CONSTANTS.width.generate_value(level);
    int grid_height = MAP_GENERATION_CONSTANTS.height.generate_value(level);
    std::mt19937 random_generator(seed);
    std::vector<std::vector<int>> grid(grid_height, std::vector<int>(grid_width, TileType::Empty));
    Leaf bsp = Leaf{
        Rect{
            Point{0, 0},
            Point{grid_width - 1, grid_height - 1}
        }
    };

    // Split the bsp and create the rooms
    split_bsp(&bsp, &grid, &random_generator, MAP_GENERATION_CONSTANTS.split_iteration.generate_value(level));
    std::vector<Rect> rooms = generate_rooms(&bsp, &grid, &random_generator);

    // Create the hallways between the rooms
    std::unordered_map<Rect, std::vector<Rect>> complete_graph;
    for (Rect room: rooms) {
        std::vector<Rect> temp;
        for (Rect x: rooms) {
            if (x != room) {
                temp.push_back(x);
            }
        }
        complete_graph.insert({room, temp});
    }
    create_hallways(&grid, &random_generator, &create_connections(&complete_graph),
                    MAP_GENERATION_CONSTANTS.obstacle_count.generate_value(level));

    // Get all the tiles which can support items being placed on them and then place the player and
    // all the items
    int item_limit = MAP_GENERATION_CONSTANTS.item_count.generate_value(level);
    std::vector<Point> possible_tiles = collect_positions(&grid, TileType::Floor);
    place_tile(&grid, &random_generator, TileType::Player, &possible_tiles);
    for (std::pair<TileType, double> item: ITEM_PROBABILITIES) {
        int tile_limit = (int) round((double) (item.second * item_limit));
        int tiles_placed = 0;
        while (tiles_placed < tile_limit) {
            place_tile(&grid, &random_generator, item.first, &possible_tiles);
            tiles_placed += 1;
        }
    }

    // Return the grid and a LevelConstants object
    return std::make_pair(grid, LevelConstants{level, grid_width, grid_height});
}

The bsp.h file:

#ifndef PRIMITIVES_H
#define PRIMITIVES_H
// Custom includes
#include "primitives.h"

#endif

// External includes
#include <random>

// ----- STRUCTURES ------------------------------
struct Leaf {
    // Parameters
    Rect container;

    // Attributes
    Leaf *left, *right;
    Rect *room;
    bool split_vertical;

    Leaf() {}

    Leaf(Rect container_val) {
        container = container_val;
    }

    bool split(std::vector<std::vector<int>> *grid, std::mt19937 *random_generator, bool debug_game) {
        // Check if this leaf is already split or not
        if (left && right) {
            return false;
        }

        // To determine the direction of split, we test if the width is 25% larger than the height,
        // if so we split vertically. However, if the height is 25% larger than the width, we split
        // horizontally. Otherwise, we split randomly
        std::uniform_int_distribution<> split_vertical_distribution(0, 1);
        bool split_vertical_val = split_vertical_distribution(*random_generator);
        if ((container.width > container.height) && ((double) (container.width / container.height) >= 1.25)) {
            split_vertical_val = true;
        } else if ((container.height > container.width) && ((double) (container.height / container.width) >= 1.25)) {
            split_vertical_val = false;
        }

        // To determine the range of values that we could split on, we need to find out if the
        // container is too small. Once we've done that, we can use the x1, y1, x2 and y2
        // coordinates to specify the range of values
        int max_size = (split_vertical_val) ? container.width - MIN_CONTAINER_SIZE : container.height -
                                                                                     MIN_CONTAINER_SIZE;
        if (max_size <= MIN_CONTAINER_SIZE) {
            // Container too small to split
            return false;
        }

        // Create the split position. This ensures that there will be MIN_CONTAINER_SIZE on each
        // side
        std::uniform_int_distribution<> pos_distribution(MIN_CONTAINER_SIZE, max_size);
        int pos = pos_distribution(*random_generator);

        // Split the container
        if (split_vertical_val) {
            // Split vertically making sure to adjust pos, so it can be within range of the actual
            // container
            pos += container.top_left.x;
            if (debug_game) {
                for (int y = container.top_left.y; y <= container.bottom_right.y + 1; y++) {
                    (*grid)[y][pos] = TileType::DebugWall;
                }
            }

            // Create the child leafs
            left = &Leaf{
                Rect{
                    Point{
                        container.top_left.x, container.top_left.y
                    },
                    Point{
                        pos - 1, container.bottom_right.y,
                    }
                }
            };
            right = &Leaf{
                Rect{
                    Point{
                        pos + 1, container.top_left.y,
                    },
                    Point{
                        container.bottom_right.x, container.bottom_right.y
                    }
                }
            };
        } else {
            // Split horizontally making sure to adjust pos, so it can be within range of the actual
            // container
            pos += container.top_left.y;
            if (debug_game) {
                for (int x = container.top_left.x; x <= container.bottom_right.x + 1; x++) {
                    (*grid)[pos][x] = TileType::DebugWall;
                }
            }

            // Create the child leafs
            left = &Leaf{
                Rect{
                    Point{
                        container.top_left.x, container.top_left.y
                    },
                    Point{
                        container.bottom_right.x, pos - 1,
                    }
                }
            };
            right = &Leaf{
                Rect{
                    Point{
                        container.top_left.x, pos + 1,
                    },
                    Point{
                        container.bottom_right.x, container.bottom_right.y
                    }
                }
            };
        }

        // Set the leaf's split direction
        split_vertical = split_vertical_val;

        // Successful split
        return true;
    }

    bool create_room(std::vector<std::vector<int>> *grid, std::mt19937 *random_generator) {
        // Test if this container is already split or not. If it is, we do not want to create a room
        // inside it otherwise it will overwrite other rooms
        if (left && right) {
            return false;
        }

        // Pick a random width and height making sure it is at least min_room_size but doesn't
        // exceed the container
        std::uniform_int_distribution<> width_distribution(MIN_ROOM_SIZE, container.width);
        int width = width_distribution(*random_generator);
        std::uniform_int_distribution<> height_distribution(MIN_ROOM_SIZE, container.height);
        int height = height_distribution(*random_generator);

        // Use the width and height to find a suitable x and y position which can create the room
        std::uniform_int_distribution<> x_pos_distribution(container.top_left.x, container.bottom_right.x - width);
        int x_pos = x_pos_distribution(*random_generator);
        std::uniform_int_distribution<> y_pos_distribution(container.top_left.y, container.bottom_right.y - height);
        int y_pos = y_pos_distribution(*random_generator);

        // Create the room rect and test if its width to height ratio will make an oddly-shaped room
        Rect rect = Rect{
            Point{
                x_pos, y_pos
            },
            Point{
                x_pos + width - 1, y_pos + height - 1
            }
        };
        if ((((double) std::min(rect.width, rect.height)) / ((double) std::min(rect.width, rect.height))) <
            ROOM_RATIO) {
            return false;
        }

        // Width to height ratio is fine so place the rect in the 2D grid and store it
        rect.place_rect(grid);
        room = &rect;

        // Successful room creation
        return true;
    }
};

The astar.h file:

#ifndef PRIMITIVES_H
#define PRIMITIVES_H
// Custom includes
#include "primitives.h"

#endif

// External includes
#include <queue>

// ----- CONSTANTS ------------------------------
/* The ID of a TileType obstacle */
const std::vector<Point> INTERCARDINAL_OFFSETS = {
    {-1, -1},
    {0,  -1},
    {1,  -1},
    {-1, 0},
    {1,  0},
    {-1, 1},
    {0,  1},
    {1,  1},
};


// ----- STRUCTURES ------------------------------
struct Neighbour {
    int cost;
    Point pair;

    inline bool operator<(const Neighbour nghbr) const {
        // The priority_queue data structure gets the maximum priority, so we need to
        // override that functionality to get the minimum priority
        return cost > nghbr.cost;
    }
};


// ----- FUNCTIONS ------------------------------
std::vector<Point> grid_bfs(Point target, int height, int width) {
    // Create a vector to store the neighbours
    std::vector<Point> result;

    // Iterate over each offset and check if it's a valid neighbour
    for (Point offset: INTERCARDINAL_OFFSETS) {
        int x = target.x + offset.x;
        int y = target.y + offset.y;
        if ((x >= 0 && x < width) && (y >= 0 && y < height)) {
            result.push_back({x, y});
        }
    }

    // Return the result
    return result;
}


std::vector<Point> calculate_astar_path(std::vector<std::vector<int>> *grid, Point start, Point end) {
    // Set up a few variables needed for the pathfinding
    std::vector<Point> result;
    std::priority_queue<Neighbour> queue;
    std::unordered_map<Point, Point> came_from = ;
    std::unordered_map<Point, int> distances = ;
    int height = (int) grid->capacity();
    int width = (int) grid[0].capacity();
    queue.push({0, start});

    // Loop until the priority queue is empty
    while (!queue.empty()) {
        // Get the lowest cost pair from the priority queue
        Point current = queue.top().pair;
        queue.pop();

        // Check if we've reached our target
        if (current == end) {
            // Backtrack through came_from to get the path
            while (!(came_from[current] == current)) {
                // Add the current pair to the result list
                result.push_back({current.x, current.y});

                // Get the next pair in the path
                current = came_from[current];
            }

            // Add the start pair and exit out of the loop
            result.push_back({start.x, start.y});
            break;
        }

        // Add all the neighbours to the heap with their cost being f = g + h:
        //   f - The total cost of traversing the neighbour.
        //   g - The distance between the start pair and the neighbour pair.
        //   h - The estimated distance from the neighbour pair to the end pair. We're using the Chebyshev distance for
        //       this.
        for (Point neighbour: grid_bfs(current, height, width)) {
            if (!came_from.count(neighbour)) {
                // Store the neighbour's parent and calculate its distance from the start pair
                came_from[neighbour] = current;
                distances[neighbour] = distances[current] + 1;

                // Check if the neighbour is an obstacle. If so, set the total cost to infinity, otherwise, set it to f = g + h
                int f_cost = ((*grid)[neighbour.y][neighbour.x] == TileType::Obstacle) ? std::numeric_limits<int>::max()
                                                                                       :
                             distances[neighbour] +
                             std::max(abs(neighbour.x - current.x), abs(neighbour.y - current.y));

                // Add the neighbour to the priority queue
                queue.push({f_cost, neighbour});
            }
        }
    }

    // Return result
    return result;
}

The primitives.h file:

// Custom includes
#include "constants.h"

// External includes
#include <unordered_map>

// ----- STRUCTURES ------------------------------
template<class T>
inline void hash_combine(size_t &seed, const T &v) {
    std::hash <T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

struct Point {
    int x, y;

    inline bool operator==(const Point pnt) const {
        return x == pnt.x && y == pnt.y;
    }

    inline bool operator!=(const Point pnt) const {
        return x != pnt.x && y != pnt.y;
    }

    Point() {}

    Point(int x_val, int y_val) {
        x = x_val;
        y = y_val;
    }

    inline std::pair<int, int> sum(Point *other) {
        return std::make_pair(x + other->x, y + other->y);
    }

    inline std::pair<int, int> abs_diff(Point *other) {
        return std::make_pair(abs(x + other->x), abs(y + other->y));
    }
};


template<>
struct std::hash<Point> {
    size_t operator()(const Point &pnt) const {
        size_t res = 0;
        hash_combine(res, pnt.x);
        hash_combine(res, pnt.y);
        return res;
    }
};

struct Rect {
    // Parameters
    Point top_left, bottom_right;

    // Attributes
    Point center;
    int width, height;

    inline bool operator==(const Rect rct) const {
        return top_left == rct.top_left && bottom_right == rct.bottom_right;
    }

    inline bool operator!=(const Rect rct) const {
        return top_left != rct.top_left && bottom_right != rct.bottom_right;
    }

    Rect() {}

    Rect(Point top_left_val, Point bottom_right_val) {
        std::pair<int, int> sum = top_left_val.sum(&bottom_right_val);
        std::pair<int, int> diff = bottom_right_val.abs_diff(&top_left_val);
        top_left = top_left_val;
        bottom_right = bottom_right_val;
        center = Point((int) round(((double) sum.first) / 2.0), (int) round(((double) sum.second) / 2.0));
        width = diff.first;
        height = diff.second;
    }

    inline int get_distance_to(Rect *other) {
        return std::max(abs(center.x - other->center.x), abs(center.y - other->center.y));
    }

    void place_rect(std::vector<std::vector<int>> *grid) {
        // Get the width and height of the grid
        int grid_height = (int) grid->size();
        int grid_width = (int) grid[0].size();

        // Place the walls
        for (int y = std::max(top_left.y, 0); y < std::max(bottom_right.y + 1, grid_height); y++) {
            for (int x = std::max(top_left.x, 0); x < std::max(bottom_right.x + 1, grid_width); x++) {
                if (std::count(std::begin(REPLACEABLE_TILES), std::end(REPLACEABLE_TILES), (*grid)[y][x]) > 0) {
                    (*grid)[y][x] = TileType::Wall;
                }
            }
        }

        // Place the floors. The ranges must be -1 in all directions since we don't want to
        // overwrite the walls keeping the player in, but we still want to overwrite walls that
        // block the path for hallways
        for (int y = std::max(top_left.y + 1, 1); y < std::max(bottom_right.y, grid_height - 1); y++) {
            for (int x = std::max(top_left.x + 1, 1); x < std::max(bottom_right.x, grid_width - 1); x++) {
                (*grid)[y][x] = TileType::Floor;
            }
        }
    }
};

template<>
struct std::hash<Rect> {
    size_t operator()(const Rect &rct) const {
        size_t res = 0;
        hash_combine(res, rct.top_left);
        hash_combine(res, rct.bottom_right);
        return res;
    }
};

The constants.h file:

// External includes
#include <algorithm>
#include <math.h>

// ----- ENUMS ------------------------------
enum TileType {
    DebugWall,
    Empty,
    Floor,
    Wall,
    Obstacle,
    Player,
    HealthPotion,
    ArmourPotion,
    HealthBoostPotion,
    ArmourBoostPotion,
    SpeedBoostPotion,
    FireRateBoostPotion
};

// ----- STRUCTURES ------------------------------
struct MapGenerationConstant {
    double base_value, increase, max_value;

    inline int generate_value(int level) const {
        return (int) std::min(round(base_value * pow(increase, level)), max_value);
    }
};

struct MapGenerationConstants {
    MapGenerationConstant width, height, split_iteration, obstacle_count, item_count;
};

// ----- CONSTANTS ------------------------------
// Defines the constants for the map generation
const MapGenerationConstants MAP_GENERATION_CONSTANTS = {
    {30, 1.2, 150},
    {20, 1.2, 100},
    {5, 1.5, 25},
    {20,1.3, 200},
    {5, 1.1, 30},
};

// Defines the probabilities for each item
const std::pair<TileType, double> ITEM_PROBABILITIES[6] = {
    {HealthPotion,        0.3},
    {ArmourPotion,        0.3},
    {HealthBoostPotion,   0.2},
    {ArmourBoostPotion,   0.1},
    {SpeedBoostPotion,    0.05},
    {FireRateBoostPotion, 0.05},
};

// Defines constants for the binary space partition
const int MIN_CONTAINER_SIZE = 5;
const int MIN_ROOM_SIZE = 4;
const double ROOM_RATIO = 0.625;

// Defines constants for hallway and entity generation
const TileType REPLACEABLE_TILES[3] = {
    Empty, Obstacle, DebugWall
};
const int HALLWAY_SIZE = 5;

Sometimes the program fails on the create_hallways function, but other times it fails on the split_bsp function and is not consistent. I think it may be because of the recursive Leaf struct and its left and right attriutes, however, I'm not sure. Any ideas why this might be occuring?

Thanks.