samedi 1 août 2020

C++: Smart Pointers & Fluent Design Pattern with References

I'm trying to learn C++ after being spoiled with high-level languages for all of my life.

I would like to use the fluent design pattern with a class, but I'm worried that I'm making a mistake somewhere and sacrificing performance.

Say that I have a class Builder, and it has some member properties and methods. All of it's methods look something like so:

Builder &doSomething(SomeTypeThatCouldBeAClassOrAPrimitive &thing)
{
    // do stuff, such as
    // modify a class member
    memberThing = "something";
    
    return *thing;
} 

And say that I'm using it like so:

unique_ptr<Builder> builder(new Builder());

builder->doSomething(someVal)
        .doAnotherThing(someOtherVal)
        .doAFinalThing(someOtherOtherVal);

Just from the code provided, am I doing something wrong, or could something be done more efficiently?

Please let me know if I need to provide more information.

Loading from file cpp

I want to load a playlist from a textfile. The text file consists of albums with their songs, the first line is the album name, the second line is the number of songs in the album, then one song with data on each line until the album is finished, then the album name of the next album etc. To make things more fun, the list is it's own class, the album it's own class and the songs their own class. Here is an example of what the file can look like

Album name1

2

song1|artist1|234

song2|artist1|443

Album name2

3

song3|artist2|320

song4|artist2|360

song5|artist2|340

My problem is that when I load, the first album will be loaded correctly, but the second album (and third etc) will not have the full name loaded, it will miss the first character. So Album name2 would be loaded as lbum name2.

This is the classes involved with the functions and overloads that are used in doing this:

#ifndef DT019G_JUKEBOX_H
#define DT019G_JUKEBOX_H

#include "Prototypes.h"
#include "Album.h"
#include "Menu.h"

class Jukebox {
private:
    std::vector <Album> albums;
    Menu mainMenu, fileMenu, printMenu;

public:
    Jukebox() {
    void openFile();


void Jukebox::openFile() {
    Album tmpAlbum;
    std::fstream inFile(directory+fileName, std::ios::in);
      while(!inFile.eof()) {inFile>> tmpAlbum;
    albums.push_back(tmpAlbum);}
    inFile.close();
}


#ifndef DT019G_ALBUM_H
#define DT019G_ALBUM_H

#include "Prototypes.h"
#include "Song.h"
class Album {
public:
    std::string albumName;
private:
    std::vector <Song> songList;
public:
    Album() {albumName="NoName";}
    Album(std::string pName) {albumName=pName;}

    //Set/Get functions
    void setAlbumName (const std::string pname) {albumName=pname;}
    void setSongList (const std::vector <Song> pSongList) {songList=pSongList;}
    void clearSongList () {songList.clear();}

    // Add a song to the albums song list
    void addSongToAlbum (const Song pSong);

};

std::istream &operator>>(std::istream &is, Album &album);
#endif //DT019G_ALBUM_H

// Overloads the >> stream so it can be used to load an album from file.
// First it puts all the input in the vector inputData. Then when the first row (containing the album name)
// has been loaded into albumName, the first two entries of inputData are erased (the ones containing the album name and
// number of songs. Then only songs are left in vector thus they can be loaded into the songList with ease.
std::istream &operator>>(std::istream &is, Album &album){
    album.clearSongList();
    std::string tempData;
    std::getline(is, tempData);
    album.setAlbumName(tempData);
    std::getline(is, tempData);
    int numberOfSongs;
    std::istringstream iss(tempData);
    iss >> numberOfSongs;
    Song tempSong;
    for (size_t i=0; i<numberOfSongs; i++){
       std::getline(is, tempData);
       std::istringstream iss(tempData);
       iss>>tempSong;
       album.addSongToAlbum(tempSong);
    }
    is.get();
    return is;
}

I add the song class here eventhough I don't think it's necessary as it seems to function as intended

class Song {
private:
    string title;
    string artist;
    Time length;
public:
    // Default constructor
    Song() {title="noTitle"; artist="noArtist"; length=Time(0,0,0);}
    // Constructor using parameters
    Song (string pTitle, string pArtist, int pHours, int pMinutes, int pSeconds)
    {title=pTitle, artist=pArtist, length=Time(pHours, pMinutes, pSeconds);}

    // Set/Get functions
    void setTitle (string pTitle) {title=pTitle;}
    void setArtist (string pArtist) {artist=pArtist;}
    void setLength (Time pTime) {length=pTime;}
    string getTitle ()const {return title;}
    string getArtist ()const {return artist;}
    Time getLength () const {return length;}

    void clientProgram();
};

// Takes an in stream on the format title | artist | time and convert it to a Song object.
std::istream &operator>>(std::istream &is, Song &song);

#endif //DT019G_SONG_H

std::istream &operator>>(std::istream &is, Song &song){
    string loadData;
    std::getline(is, loadData);
    string tempSeconds;
    Time tempTime;
    size_t j,k,l;
    j=loadData.find(DELIM);
    k=loadData.find(DELIM, j+1);
    l=loadData.size();
    song.setTitle(loadData.substr(0,j));
    song.setArtist(loadData.substr(j+1,k-(j+1)));
    tempSeconds=loadData.substr(k+1, l-(k+1));
    std::istringstream iss(tempSeconds);
    iss >>tempTime;
    song.setLength(tempTime);
    is.get();
    return is;
}

Thanks for any help. I just can't find the reason for this to happen myself.

Implement list with compare_exchange (std:atomic)

I am trying to find proven code of implemented list using std::atomics hence thread safe/lock free. According to this conference, it can be done. But yet, all I find is examples of queue or stacks.

https://github.com/CppCon/CppCon2017/blob/master/Presentations/C%2B%2B%20Atomics%2C%20From%20Basic%20to%20Advanced/C%2B%2B%20Atomics%2C%20From%20Basic%20to%20Advanced%20-%20Fedor%20Pikus%20-%20CppCon%202017.pdf

How is #define S64_MIN defined in linux data types?

I am trying to understand the definition of a linux macro S64_MIN used in the following else condition i.e. draw = S64_MIN.

Which exact decimal value is meant here for S64_MIN?

        if (weights[i]) 
          {
            u = hash(bucket->h.hash, x, ids[i], r);
            u &= 0xffff;
            ln = crush_ln(u) - 0x1000000000000ll;
            
            __s64 draw = div64_s64(ln, weights[i]);
        } 
else   
       {
            __s64 draw = S64_MIN;  
           
          // #define S64_MAX    ((s64)(U64_MAX >> 1))
          // #define S64_MIN    ((s64)(-S64_MAX -1))
       }
        if (i == 0 || draw > high_draw) 
            
          {
            high = i;
            high_draw = draw;
          }
    }
    return bucket->h.items[high];
}

Move constructor should be called by default

In following case where i have created move ctor in Integer class, i am expecting that it should be called by default on rvalue reference while creating Product object but i am getting call of copy constructor only. Gcc - 7.5.0 on Ubuntu 18

#include<iostream>
using namespace std;

class Integer 
{
    int *dInt = nullptr;
public: 
    Integer(int xInt)  {
        dInt = new int(xInt);
        cout<<"Integer Created"<<endl;
    } 
    Integer(const Integer &xObj)
    {
        cout<<"Copy called"<<endl;
        dInt = new int(xObj.mGetInt());
    }

    Integer(Integer &&xObj)
    {
        cout<<"Move called"<<endl;
        dInt = xObj.dInt;
        xObj.dInt = nullptr;
    }

    Integer& operator=(const Integer &xObj)
    {
        cout<<"Assignment operator called"<<endl;
        *dInt = xObj.mGetInt();
        return *this;
    }

    Integer& operator=(Integer &&xObj)
    {
        cout<<"Move Assignment operator called"<<endl;
        delete dInt;
        dInt = xObj.dInt;
        xObj.dInt = nullptr;
        return *this;   
    }
    ~Integer() 
    {
        cout<<"Integer destroyed"<<endl;
        delete dInt;
    }

    int mGetInt() const {return *dInt;}
};

class Product 
{
    Integer dId;
public: 
    Product(Integer &&xId)
    :dId(xId)
    {

    }
};
int main () 
{
    Product P(10); // Notice implicit conversion of 10 to Integer obj.
}

In above case, move called if i use dId(std::move(xId)) in Product class ctor, I was expecting it should called by default on rvalue reference. In following case i couldn't avoid creating of temporary object of Integer class, Is there any good way to avoid creating of temporary object.

    Product(const Integer &xId)
    :dId(xId)
    {

    }
    
    Product(10); // inside main

My purpose of above question to build my understanding so that i can utilize temporary object memory better.

RTSP encoded Stream storage - Using OpenCV/C++

I hope all are doing great.

I am trying to do the RTSP video streaming display as well as storage. as shown in the following figure.

Working-flow-diagram The below Gstreamer pipeline is working fine for the following two task.

  1. Capture, decode and display.

  2. Capture & store the same stream into a file (without any decoding operation).

    gst-launch-1.0 -e rtspsrc location=rtsp://admin:888888@192.168.5.21:5001/udp/av0_0 ! rtph264depay ! h264parse ! tee name=t ! queue ! omxh264dec ! videoconvert ! queue ! autovideosink sync=false async=false t. ! queue ! mp4mux ! filesink location=out.mp4

Now, In order to process the frames, I have to perform the above similar task in the C++/OpenCV programming,

  1. Capture the RTSP encoded video stream, decode and process it.
  2. Capture & Store the incoming encoded RTSP video stream into the file without performing decoding operation on it using openCV/C++ programming.

The first task is doable using the OpenCV code shown below.

VideoCapture cap("rtspsrc location=rtsp://admin:888888@192.168.5.21:5001/udp/av0_0 ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! appsink sync=false async=false",cv::CAP_GSTREAMER);

cap.read(img);
process(img);
  • Problem I have tried a couple of ways to do the second task but I could not able to do it.

I have tried the following code that can store the video stream in a file but not able to play stored output.mp4 file due to the wrong storage frames.

cv::VideoCapture cap ("-e rtspsrc location=rtsp://admin:888888@192.168.5.21:5001/udp/av0_0 ! rtph264depay ! h264parse ! tee name=t ! queue ! omxh264dec ! videoconvert ! queue ! appsink t. ! queue  ! filesink location=out.mp4");

cap.read(img);
process(img);
cv::imshow(img);

It would be greatly appreciated if anyone can guide me to do the second task (capture and store the Input encoded stream to a file).

Extract words from a file and put them into a `std::vector` of `std::array

The following is the file(ka.txt) from which I want to read lines :-

ASD|BSD|CSdsa|ood
fmads|aok|pdski
kdijf|okmdsomf|opkasd|okd
asdas
kamkd|aoda|kked|ok

The following is the code that I've written to put this data into a vector of std::array<std::string, 4>.

#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <fstream>
#include <sstream>
int main(){
        std::fstream file("ka.txt");
        std::vector<std::array<std::string, 4>> darr; darr.reserve(5);
        std::array<std::string, 4> istd;
        std::string * line = new std::string; std::string * word = new std::string;
        while(std::getline(file, *line)){
                std::stringstream ss(*line);
                int per = 0;
                while(!ss.eof()){
                        std::getline(ss, *&istd[per], '|');
                        per++;
                }       
                darr.emplace_back(istd);
        }       
        file.close();
        
        for(int i = 0; i < darr.size(); i++){
                for(int j = 0; j < 4; j++){
                        std::cout << darr[i][j] << "\t";
                }       
                std::cout << "\n";
        }       
  
        return 0;       
}

Basically, I have a vector which has std::array's and each std::array is of size 4. So I am reading the data from the file with | delimiter. And I want to store each element in every row of the text file as a std::array. And storing these std::arrays in one vector. Also, if one row has 4 elements separated by |, then there should be four elements in the std::array. If there is only one element in the row, then there should be only one element in the std::array So when I run this code I get the following output:-

ASD BSD CSdsa   ood 
fmads   aok pdski       
kdijf   okmdsomf    opkasd  okd 
asdas       opkasd  okd 
kamkd   aoda    kked    ok  

So, the fourth row has a wrong std::array since it should only have one element, but instead it should have only one. How can I achieve this?

Also, I think the probable problem is in the while loop which begins at line 12 of the code.