std::make_shared initializes user type differently from the std::shared_ptr(new USER_TYRE), where USER_TYRE is a child class to an abstract

I cannot believe my eyes I’ve meet this problem that seems to be impossible according to documentation. std::make_shared<USER_TYRE> initializes user type differently from the std::shared_ptr(new USER_TYRE), where USER_TYRE is a child class to an abstract one.

  1. auto p_obj = std::make_shared<USER_TYRE>(1);
  2. std::shared_ptr<USER_TYRE> p_obj (new USER_TYRE(1));
  3. auto p_obj = USER_TYRE(1);
    USER_TYRE publically iherit abstract class.
    And the first case initialise the USER_TYRE differently from two other and incur the application crash. First case demonstrate non anticipated behavior unlike the others. Before abstract class made there were no problems.

To explain this I should say all background and details how I met this problem.

I had been using the Qt Creator 13.0.0 (Community) IDE to create GUI application kind of calculator.
Firstly I had written a working instance. First working instance correctly worked with the std::make_shared<USER_TYRE> and everything had anticipated results, all relized functions of the app worked correctly. After that I’ve decided that I should to rewrite this app according to SOLID principles, especially to Liskov substitution principle.
I had types as expression_element, value and operators classes, all derived from the expression_element. Because of that expression_element had more mentioned virtual methods that any of the child classes has realized. And this ocasion has violated Liskov substitution principle and expression_element was available to use for the object creating. After that I have decided to make that better.
The next my step was to reorganize the classes relations: to make the classes not assumed to be used for the object creation as abstract classes, and some expression_element virtual methods should be relocated to the derived abstract classes as value_interface and operator_interface.
So I made this in the way I demonstrate below:

My file “expression_element_interface.h”:

#ifndef EXPRESSION_ELEMENT_INTERFACE_H
#define EXPRESSION_ELEMENT_INTERFACE_H
#include <memory>

class expression_element
{
private:
    const int element_type;
protected:
    enum {VALUE = 0, OPERATOR = 1, BRACKETED_EXPRESSION = 2, FUNCTION = 3};
    expression_element(int _type) : element_type(_type) {}
    virtual ~expression_element() = 0;
public:
    inline int get_element_type() const {return element_type;}
    bool operator==(const expression_element& it) const { return this->element_type == it.element_type; }
    friend bool isvalue(const expression_element&);
    friend bool isoperator(const expression_element&);
    friend bool isbracked(const expression_element&);
    friend bool isfunction(const expression_element&);
};

class value_interface : public expression_element
{
private:
    const long double contained_value;
protected:
    value_interface(long double _value) : expression_element(VALUE), contained_value(_value)  {}
public:
    virtual ~value_interface() = 0;
    long double get_contained_value() const { return contained_value; }
    friend bool samevalue(const value_interface&,const value_interface&);
};

class operator_interface : public expression_element
{
private:
    const int operator_type;
protected:
    enum { SUMMATOR = 0, SUBTRACTOR = 1, MULTIPLIER = 2, DIVIDER = 3};
    operator_interface(int _operator_type) : expression_element(OPERATOR), operator_type(_operator_type) {}
    virtual long double toCalculate(long double, long double) const = 0;
public:
    virtual ~operator_interface() = 0;
    virtual std::shared_ptr<value_interface> operator_apply(const std::shared_ptr<value_interface> it_1,const std::shared_ptr<value_interface> it_2) const = 0;
    virtual std::shared_ptr<value_interface> operator_apply(const value_interface& it_1,const value_interface& it_2) const = 0;
    inline int get_operator_type() const {return operator_type;}
    friend bool issummator(const operator_interface&);
    friend bool issubtractor(const operator_interface&);
    friend bool ismultiplier(const operator_interface&);
    friend bool isdivider(const operator_interface&);
};
#endif // EXPRESSION_ELEMENT_INTERFACE_H

My file “expression_element_interface.cpp”:

#include "expression_element_interface.h"

expression_element::~expression_element() {}
bool isvalue(const expression_element& it) { return it.element_type == expression_element::VALUE; }
bool isoperator(const expression_element& it) { return it.element_type == expression_element::OPERATOR; }
bool isbracked(const expression_element& it) { return it.element_type == expression_element::BRACKETED_EXPRESSION; }
bool isfunction(const expression_element& it) { return it.element_type == expression_element::FUNCTION; }

value_interface::~value_interface() { expression_element::~expression_element(); }
bool samevalue(const value_interface& it_1,const value_interface& it_2)
{
    return it_1.contained_value == it_2.contained_value;
}

operator_interface::~operator_interface(){ expression_element::~expression_element(); }
bool issummator(const operator_interface& it) { return it.operator_type == operator_interface::SUMMATOR; }
bool issubtractor(const operator_interface& it) { return it.operator_type == operator_interface::SUBTRACTOR; }
bool ismultiplier(const operator_interface& it) { return it.operator_type == operator_interface::MULTIPLIER; }
bool isdivider(const operator_interface& it) { return it.operator_type == operator_interface::DIVIDER; }

My file “value.h”:

#ifndef VALUE_H
#define VALUE_H
#include "expression_element_interface.h"

class value : public value_interface
{
public:
    value(long double _value) : value_interface(_value) {}
};

#endif // VALUE_H

My file “operator.h” (only the summator class part of all of them, other have the same structure):

class summator : public operator_interface
{
private:
    long double toSum(long double _it_1, long double _it_2) const { return _it_1 + _it_2; }
    long double toCalculate(long double _it_1, long double _it_2) const override { return toSum(_it_1, _it_2); }
public:
    summator() : operator_interface(SUMMATOR) {}
    ~summator() {}
    std::shared_ptr<value_interface> operator_apply(const std::shared_ptr<value_interface> it_1,const std::shared_ptr<value_interface> it_2) const override
    {
        return std::make_shared<value>( this->toCalculate( it_1->get_contained_value(), it_2->get_contained_value() ) );
    }
    virtual std::shared_ptr<value_interface> operator_apply(const value_interface& it_1,const value_interface& it_2) const override
    {
        return std::make_shared<value>( this->toCalculate(it_1.get_contained_value(), it_2.get_contained_value() ) );
    }
};

After I restructurized my classes I started rewriting my old code to adjust it for the new data types using.
I had two more classes:
transformator_strToExpression –> to convert a const char* input in the calculator to the std::liststd::shared_ptr<expression_element>.
solver –> receive const char* input from the calculator, use the transformator_strToExpression object to convert the input to std::liststd::shared_ptr<expression_element>, save it and start the calculations (find the certain type of operator take neighbour objects and use in the method of the operator. Result value replace three object by itself: previous object, operator object, next object. Finally in std::list will remain only the one value object in the std::shared_ptr<expression_element> format).

The problem have been met in the convert step in the transformator_strToExpression class.
To explain demonstrate the conditions of this problem appear I should to show details of this class:
My file “transformator_strtoexpression.h”:

#ifndef TRANSFORMATOR_STRTOEXPRESSION_H
#define TRANSFORMATOR_STRTOEXPRESSION_H
#include "expression_element_interface.h"
#include "value.h"
#include <list>
#include <memory>

#include <QDebug> // Feel free to delete this string

class transformator_strToExpression
{
private:
    std::list<std::shared_ptr<expression_element>>& convert_to_object(const char*, std::list<std::shared_ptr<expression_element>>&) const;
    std::list<std::shared_ptr<expression_element>>& make_valid(std::list<std::shared_ptr<expression_element>>&) const;
    //Feel free to delete this below:
    void toDebug(const std::list<std::shared_ptr<expression_element>>& expression) const;
    //end
public:
    void transform(const char*, std::list<std::shared_ptr<expression_element>>&) const;
};

#endif // TRANSFORMATOR_STRTOEXPRESSION_H

The next my file will be a realisation of the transformator_strToExpression class definition.
All the comments have been made for myself (all “delete” comments).
And I should to mention that provided file have been changed to demonstrate this problem. Those changes you will find in transformator_strToExpression::convert_to_object() method in the if (isdigit(temp)) condition. Explanations of them will be later.
My file “transformator_strtoexpression.cpp”:

#include "transformator_strtoexpression.h"
#include "value.h"
#include "operator.h"
#include <sstream>

using elem_i = expression_element;
using array = std::list<std::shared_ptr<elem_i>>;
using oper_i = operator_interface;
using val_i = value_interface;


void transformator_strToExpression::transform(const char* _cstr, array& expression) const
{
    convert_to_object(_cstr, expression);
    qDebug() << "AFTER convert_to_object()";
    transformator_strToExpression::toDebug(expression);
    make_valid(expression);
    qDebug() << "AFTER make_valid()";
    transformator_strToExpression::toDebug(expression);
}

array& transformator_strToExpression::convert_to_object(const char* _cstr, array& expression) const
{
    std::istringstream istream(_cstr);
    char temp;
    long double val;
    temp = istream.peek();
    while (temp != EOF)
    {
        temp = istream.peek();
        if (isdigit(temp))
        {
            qDebug() << "digit"; ///delete
            istream >> val;
            auto b = value(val);
            auto a = std::make_shared<value>(val);
            std::shared_ptr<value> c (new value(val));
            expression.push_back(std::static_pointer_cast<elem_i>(a));
            ///delete
            auto j = std::static_pointer_cast<val_i>(a);
            qDebug() << double(val) << " " << a->get_element_type() << ": "
                     << double( a->get_contained_value() );
            qDebug() << double(val) << " " << b.get_element_type() << ": "
                     << double( b.get_contained_value() );
            qDebug() << double(val) << " " << c->get_element_type() << ": "
                     << double( c->get_contained_value() );
            ///delete end
        }
        else if (ispunct(temp))
        {
            switch(temp)
            {
            case '+':
                qDebug() << "+"; ///delete
                istream >> temp; expression.push_back(std::static_pointer_cast<elem_i>(std::make_shared<summator>()));
                break;
            case '-':
                qDebug() << "-"; ///delete
                istream >> temp; expression.push_back(std::static_pointer_cast<elem_i>(std::make_shared<subtractor>()));
                break;
            case '*':
                qDebug() << "*";///delete
                istream >> temp; expression.push_back(std::static_pointer_cast<elem_i>(std::make_shared<multiplier>()));
                break;
            case '/':
                qDebug() << "/";///delete
                istream >> temp; expression.push_back(std::static_pointer_cast<elem_i>(std::make_shared<divider>()));
                break;
            case '.':
            {
                qDebug() << ".";///delete
                istream >> temp;
                std::string str("0.");
                temp = istream.peek();
                if (isdigit(temp))
                {
                    qDebug() << "->digit";///delete
                    istream >> val;
                    str += std::to_string(val);
                    val = std::stold(str);
                    expression.push_back(std::static_pointer_cast<elem_i>(std::make_shared<value>(val)));
                    continue;
                }
            }
            break;
            default:
                qDebug() << "Transformator Error: undefined 'punct'"; istream >> temp;
            }
        }
        else
        {
            qDebug() << "Transformator Error: undefined symbol"; istream >> temp;
        }
    }
    return expression;
}

array& transformator_strToExpression::make_valid(array& expression) const
{
    // EQUATION TO CALCULATIVE FORM TRANSFORMATION
    if (!isvalue(**std::begin(expression))) expression.insert(std::begin(expression), std::make_shared<value>(0));
    for (auto it = std::begin(expression); it != --std::end(expression); std::advance(it,1))
    {
        auto it_next = it;
        std::advance(it_next,1);
        if (*it != *std::rbegin(expression))
            if ( !isvalue(**it) && !isvalue(**it_next) ) expression.erase(it);
    }
    auto it = std::end(expression);
    std::advance(it,-1);
    if (!isvalue(**it)) expression.erase(it);
    return expression;
}

//Feel free to delete this below:
void transformator_strToExpression::toDebug(const array& expression) const
{
    for (auto i = std::begin(expression); i != std::end(expression); std::advance(i,1))
    {
        if (isvalue(**i))
        {
            auto j = std::static_pointer_cast<val_i>(*i);
            qDebug() << j->get_element_type() << ": "
                     << double( j->get_contained_value() );
        }
        else if (isoperator(**i))
        {
            auto j = std::static_pointer_cast<oper_i>(*i);
            qDebug() << j->get_element_type() << ": "
                     << j->get_operator_type();
        }
    }
}
//end

So there is time to show the problem after the background have been provided:

We are going to the transformator_strToExpression::convert_to_object() method in the if (isdigit(temp)) condition:

qDebug() << "digit"; ///delete
            istream >> val;
            auto b = value(val);
            auto a = std::make_shared<value>(val);
            std::shared_ptr<value> c (new value(val));
            expression.push_back(std::static_pointer_cast<elem_i>(a));
            ///delete
            auto j = std::static_pointer_cast<val_i>(a);
            qDebug() << double(val) << " " << a->get_element_type() << ": "
                     << double( a->get_contained_value() );
            qDebug() << double(val) << " " << b.get_element_type() << ": "
                     << double( b.get_contained_value() );
            qDebug() << double(val) << " " << c->get_element_type() << ": "
                     << double( c->get_contained_value() );
            ///delete end

You can see three lines:

  1. auto b = value(val);
  2. auto a = std::make_shared<value>(val);
  3. std::shared_ptr<value> c (new value(val));
    They perform initialization of the value class in three way that must be identical to each other.
    I verified this assertment in differnt ways:
    I executed the program in the debug regime (I am doing it rigth in the same time of the writin it again).

So there is an algorithm:

I input in calculator the const char* with the content “1+1” and start calculations with button “=”.
When debug process on stage of the line auto j = std::static_pointer_cast<val_i>(a);
Those three lines has been processed.
And there are the next statment of all variables within this function:

    _cstr   "1+1"   char*
            '1'     49      0x31    char
            '+'     43      0x2b    char
            '1'     49      0x31    char
    a   @0x2652910c850  std::shared_ptr<value>
        [value_interface]   @0x2652910c850  value_interface
            [expression_element]    @0x2652910c850  expression_element
                [vptr]  _vptr.expression_element     
                    [0] 0x7ff731404a90 <value::get_val() const> void*
                    [1] 0x7ff7314049b0 <equation_element::to_calculate(long double, long double) const> void*
                element_type    0   int
            contained_value <invalid float value>   long double
    b   @0xd2e4ffaf00   value
        [value_interface]   @0xd2e4ffaf00   value_interface
            [expression_element]    @0xd2e4ffaf00   expression_element
                [vptr]  _vptr.expression_element     
                element_type    0   int
            contained_value 1   long double
    c   @0x265290b2f20  std::shared_ptr<value>
        [value_interface]   @0x265290b2f20  value_interface
            [expression_element]    @0x265290b2f20  expression_element
                [vptr]  _vptr.expression_element     
                    [0] 0x7ff731404a90 <value::get_val() const> void*
                    [1] 0x7ff7314049b0 <equation_element::to_calculate(long double, long double) const> void*
                element_type    0   int
            contained_value 1   long double
    expression  <1 элемент> array &
        [0] @0x2652910c850  std::shared_ptr<expression_element>
            [value_interface]   @0x2652910c850  value_interface
                [expression_element]    @0x2652910c850  expression_element
                    [vptr]  _vptr.expression_element     
                    element_type    0   int
                contained_value -0.0    long double
    istream @0xd2e4ffaf70   std::istringstream
    j   @0x80   std::shared_ptr<value_interface>
        [expression_element]    @0x80   expression_element
        contained_value <недоступно>    long double
    temp    '1'     49      0x31    char
    this    @0xd2e4ffb52f   transformator_strToExpression
    val 1   long double

We can see that contained_value is 1 in long double in the b and c object BUT in the a object contained_value is long double. This fact drives me crazy. How can be possible???
The next way to be assured is use the consol output, where the qDebug() helps. qDebug() can be used as the std::cout. And when i do the “1+1” input then the console output is the next:
digit
1 0 : nan
1 0 : 1
1 0 : 1
The lines for output are:

            ///delete
            auto j = std::static_pointer_cast<val_i>(a);
            qDebug() << double(val) << " " << a->get_element_type() << ": "
                     << double( a->get_contained_value() );
            qDebug() << double(val) << " " << b.get_element_type() << ": "
                     << double( b.get_contained_value() );
            qDebug() << double(val) << " " << c->get_element_type() << ": "
                     << double( c->get_contained_value() );
            ///delete end

After that I continue the application running ant it crashes with the message in translation:

The application has been terminated because it received signal from the operation system.
Signal: SIGSEGV
Appointment: Segmentation fault

I have made everything I able to do to find the explanations for this problem. Every sourse say all auto p_obj = std::make_shared<USER_TYRE>(1); and std::shared_ptr<USER_TYRE> p_obj (new USER_TYRE(1)); are indentical
+
auto p_obj = std::make_shared<USER_TYRE>(1); and auto p_obj = USER_TYRE(1); call all of the USER_TYRE constructors in the same way.
There must not be any of differece in result!
But they are!
I tried to use Copilot to explain and reveiw my code and he made the same conclusion.
I have not found any of the similar problems anywhere wherenever I tried to find.

Can someone find the explanations for this, please?

What have happened here? What is the cause of this problem? (Essentially I can start avoid std::make_shared<> for avoid this problem but that is NOT the SOLUTION of this problem and nor explanation)

Thank you for tries in advance and my respect!

P.S. If you will have some rebuke for me please say it, if there will be some recommendations how I could write code better please say it!

New contributor

Pavlo Tkach is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật