jeudi 1 juillet 2021

Avoid using of boost optional in case there is no need to copy object

Note: It's actually a continuation of question: G++-11 destruction order changed from G++9

We discovered, that we use UB thing (order of temporary objects constructors) everywhere in code, so we decide to slightly rewrite one of the code pieces. Suppose we have the following code in one of the third-party libraries (SOCI actually), this library doesn't use move semantics in the version, that we use, so, I just added it to it (look on comments):

#include <iostream>
#include <string>

#include <boost/optional.hpp>
/* trick namespace was added by me */
namespace trick
{

template<typename T>
struct maybe_holder
{
public:
   maybe_holder() = default;
   maybe_holder(T&& v) : value(v)
   {
   }

   boost::optional<T> value;
};

}

struct base_use_type
{
    base_use_type(void* v) : value(v) {}
    void* value;
};

/* NOTE: only base_use_type was parent of this class */
template <typename T>
class use_type : private trick::maybe_holder<T>, public base_use_type
{
public:
    use_type(T& t) :
    base_use_type(&t)
    {
        std::cout << "called ref ctor" << std::endl;
    }
    
    use_type(T const& t) :
    base_use_type(&const_cast<T&>(t))
    {
        std::cout << "called cref ctor" << std::endl;
    }
    /* NOTE: this was added by me */
    use_type(T&& t)
        : trick::maybe_holder<T>(std::forward<T>(t)), base_use_type(&trick::maybe_holder<T>::value.get())
   {
        std::cout << "called rvalue ctor" << std::endl;
   }
};

template <typename T>
use_type<T> do_use(T & t)
{
    return (use_type<T>(t));
}

template <typename T>
use_type<T> do_use(T const & t)
{
    return (use_type<T>(t));
}
/* NOTE: this was added by me */
template<typename T>
use_type<T> do_use(T && t)
{
    return (use_type<T>(std::forward<T>(t)));
}

int main()
{
    do_use(std::string("abc"));
    std::string s;
    do_use(s);
    const std::string ss = "11";
    do_use(ss);
}

live example

We use such kind of code in real code with something like:

   class A {
   public:
      A(const std::string& a, const std::string& b, const std::string& c) :
         a_(a), b_(b), c_(c)
      {
      }
      std::string get_a() const { return a_; }
      std::string get_b() const { return b_; }
      std::string get_c() const { return c_; }
   private:
      std::string a_;
      std::string b_;
      std::string c_;
   };
   const std::string a = std::string(500, 'a');
   const std::string b = std::string(500, 'b');
   const std::string c = std::string(500, 'c');

   A o(a, b, c);
   auto& sql = get_session();
   for (int i = 0; i < 10; ++i)
   {
      sql << "insert into temporary_strings_table (a, b, c) values (:a, :b, :c)",
          do_use(o.get_a()),
          do_use(o.get_b()),
          do_use(o.get_c());
   }

Note: it's just a simple example. It's connected with SQL, so, we cannot just make a copy every time use is called (cause, there are out variables in PL/SQL, or for example returning into in Oracle).

I'm trying to understand, is there is any way to avoid memory overhead of boost::optional in maybe_holder? Thanks in advance.

Copy object only if needed

We discovered, that we use UB thing (order of temporary objects constructors) everywhere in code, so we decide to slightly rewrite one of code pieces. Suppose we have following code:

#include <iostream>
#include <string>

#include <boost/optional.hpp>

namespace trick
{

template<typename T>
struct maybe_holder
{
public:
   maybe_holder() = default;
   maybe_holder(T&& v) : value(v)
   {
   }

   boost::optional<T> value;
};

}

struct some_base_type
{
    some_base_type(void* v) : value(v) {}
    void* value;
};

template <typename T>
class some_type : private trick::maybe_holder<T>, public some_base_type
{
public:
    some_type(T& t) :
    some_base_type(&t)
    {
        std::cout << "called ref ctor" << std::endl;
    }
    
    some_type(T const& t) :
    some_base_type(&const_cast<T&>(t))
    {
        std::cout << "called cref ctor" << std::endl;
    }

    some_type(T&& t)
        : trick::maybe_holder<T>(std::forward<T>(t)), some_base_type(&trick::maybe_holder<T>::value.get())
   {
        std::cout << "called rvalue ctor" << std::endl;
   }
};

template <typename T>
some_type<T> do_smth(T & t)
{
    return (some_type<T>(t));
}

template <typename T>
some_type<T> do_smth(T const & t)
{
    return (some_type<T>(t));
}

template<typename T>
some_type<T> do_smth(T && t)
{
    return (some_type<T>(std::forward<T>(t)));
}

int main()
{
    do_smth(std::string("abc"));
    std::string s;
    do_smth(s);
    const std::string ss = "11";
    do_smth(ss);
}

live example

Now it works fine on any kind of object (temporary will be copied to optional, then pointer to value constructed before other base class would be gotten). So, basically question is, is there is any way to avoid overhead from optional and simply not depend on it? Thanks in advance.

I tried to write something like this:

template<typename T>
struct maybe_object {};
    
template<typename T>
struct maybe_object<T&&>
{
public:
    maybe_object(T&& v) : value(std::forward(v)) {}
    typename std::remove_reference<T>::type value;
};

But as far as I see we can't use this thing, cause it's just dependent on type of template.

Create a block object that holds a content file [closed]

I was planning to create a block object. Here is my sample reference for creating it. Thank you!

void* raw = malloc(blocksize);

            std::shared_ptr<void> sharedData(raw, free) ;

//          std::cerr << "Processing block: " << blocks << "\n";
            len = fread((void*)raw, sizeof(char), blocksize, stdin);

            if (len != blocksize)
            {
                goto end;
            }

            last_range = ranges;

            Data *data = new Data(sharedData, blocksize, raw, len);

Why is my overloaded subscript operator for rvalue not called

I have looked up and down stack overflow and keep finding the same examples which I think I have implemented. I am trying to implement an associative array. I know there is std::map but I'd like to do the implementation myself for better control and better understanding.

I have overloaded the subscript operator for lvalue and rvalue. However in my code only the method for the lvalue is called and I can't find where I am mistaken. Can anyone point me in the right direction, please? Here's my code for the class. For now, it's not supposed to be efficient, just working would make me happy:

template<typename K, typename V>
class AssocArray {

private:
    size_t _arraySize = 0;
    K *_keyArray = nullptr;
    V *_valueArray = nullptr;

    void expandValueArray() {
        auto newValueArray = new V[_arraySize];
        // copy old values
        for (size_t i = 0; i < _arraySize - 1; ++i)
            newValueArray[i] = _valueArray[i];
        if (_valueArray)
            delete[] _valueArray;
        _valueArray = newValueArray;
    }

    void appendToKeyArray(K key) {
        auto newKeyArray = new K[_arraySize];
        // copy old keys
        for (size_t i = 0; i < _arraySize - 1; ++i)
            newKeyArray[i] = _keyArray[i];
        newKeyArray[_arraySize - 1] = key;
        delete[] _keyArray;
        _keyArray = newKeyArray;
    }

    bool keyExists(K key) {
        for (size_t i = 0; i < _arraySize; ++i)
            if (_keyArray[i] == key)
                return true;
        return false;
    }

    size_t getExistingKeyIndex(K key) {
        for (size_t i = 0; i < _arraySize; ++i)
            if (_keyArray[i] == key)
                return i;
    }

public:
    ~AssocArray() {
        delete[] _valueArray;
        delete[] _keyArray;
    }

    V operator[](K key) const {
        if (keyExists(key))
            return _valueArray[getExistingKeyIndex(key)];
        else
            throw std::out_of_range("Key does not exist");
    }

    V &operator[](K key) {
        if (keyExists(key))
            return _valueArray[getExistingKeyIndex(key)];

        // key does not exist
        ++_arraySize;
        appendToKeyArray(key);
        expandValueArray();
        return _valueArray[_arraySize - 1];
    }

    void print() {
        std::cout << "Content of AssocArray:" << std::endl;
        if (!_arraySize) std::cout << "none" << std::endl;
        for (int i = 0; i < _arraySize; ++i) {
            std::cout << "[" << _keyArray[i] << "] => " << _valueArray[i] << std::endl;
        }
    }
};

and here is how I call it and produce the undesired behavior:

#include <iostream>
#include "AssocArray.h"

int main() {
       AssocArray<std::string, std::string> assocArray;

        (assocArray)["Toni"] = "seven";
        (assocArray)["Sam"] = "five";
        std::cout << "assocArray before lookup of non existing key:" << std::endl << std::endl;
        assocArray.print();
        // FixMe: appends key to assocArray, but shouldn't
        std::cout << std::endl << "lookup of non existing key:" << std::endl;
        auto key = "Megan";
        std::cout << "[" << key << "] => " << assocArray[key] << std::endl << std::endl;

        std::cout << "assocArray after lookup of non existing key:" << std::endl;
        assocArray.print();
}

The output is this (see that Megan is added to the array where it shouldn't be):

assocArray before lookup of non existing key:

Content of AssocArray:
[Toni] => seven
[Sam] => five

lookup of non existing key:
[Megan] => 

assocArray after lookup of non existing key:
Content of AssocArray:
[Toni] => seven
[Sam] => five
[Megan] => 

Why don't I get an exception? Why is the overloaded method for the lvalue called here? Thanks for looking into this.

Indexing std::vector

I want to run a simple program in C++ in which there are two vectors - one is a std::vector<int> and the other is a std::vector<bool> of equal length. The value of the boolean vector at an index decides whether the value of the integer vector will be printed or not. Here is a copy of the program I am trying to run:

#include<bits/stdc++.h>
using namespace std;

int main(){
    vector<int> arr{1, 2, 3, 4, 5};
    vector<bool> b(true, arr.size());

    for(int i=0; i<arr.size(); i++){
        if(b[i])
            cout<<arr[i]<<endl;
    }
    return 0;
}

The above program runs as expected. But there is an Address Boundary Error encountered when I change the values from true to false in the std::vector initialization line. Precisely, the error is:

fish: Job 1, './test_vector_bool' terminated by signal SIGSEGV (Address boundary error)

I am already aware of some of the major pitfalls of using vector<bool> from these threads:

What I gathered from these threads is we should not be using reference for vector<bool> in cpp. But all I need to know is why is the vector with true working and initialization with false failing?

Is there a way to use a matrix larger than 4x4?

I need to create matrices that are larger then mat4. (ex: 7x7, 7x6) and apply functions such as transpose and inverse as well as multiplications with vectors (ex: vec7, vec6).

Is there a way to implement a matrix and vector that are bigger than what is provided?

I have tried the following:

1.

typedef mat<6, 6, float, defaultp>  mat6;

This gives me "Implicit instantiation of undefined template"

2. I'm pretty sure I can use several smaller matrices and kind of assume they are together but this makes the code hard to understand for others and becomes very messy.

why this opendds messenger link error when i use c++11

background: OS: Centos7.9 x64 compiler: g++4.8.5 OpenDDS-3.14( configure --std=c++11)

I want to compile the OpenDDS-3.14/ tests/cmake_integration/Messenger/Messenger_1,i add one line " set(CMAKE_CXX_STANDARD 11)" to the CMakeLists.txt, then i cmake . and make, but it link error, some undefined reference occours,if i do not add set(CMAKE_CXX_STANDARD 11),it is ok. how to solve this problem? thank you.