Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22201

C++ Queue::Pop function acts weird when compiled with -O1

$
0
0

I have been writing my own queue in c++.The problem is that it has a function called Queue::Pop() which calls the destructor of the first item in the queue which is kept track of by an index called _First, and afterwards _First is incremented and _Length is decremented.When normally compiled, it performs as expected, however when -O1 flag is added, it starts acting weird and does not call the object's destructor properly.The printing in destructor happens but the Id is not set to -1.and as result, when the queue goes out of the scope, the memory is delete[] ed and destructors are called again and that is invalid code since if it was a file descriptor, it would be closed twice.here is the Pop function:

#include <iostream>#include <tuple>#include <memory>#include <sys/uio.h>#include <initializer_list>namespace Core{    namespace Iterable    {        template <typename T>        class Span        {        private:            size_t _Length = 0;            T *_Content = nullptr;            inline T &_ElementAt(size_t Index)            {                return this->_Content[Index];            }            inline const T &_ElementAt(size_t Index) const            {                return this->_Content[Index];            }        public:            Span() = default;            Span(size_t Size) : _Length(Size), _Content(new T[Size]) {}            Span(size_t Size, const T &Value) : _Length(Size), _Content(new T[Size])            {                for (size_t i = 0; i < _Length; i++)                {                    _Content[i] = Value;                }            }            Span(Span &&Other) : _Length(Other._Length), _Content(Other._Content)            {                Other._Content = nullptr;                Other._Length = 0;            }            Span(const Span &Other) : _Length(Other._Length), _Content(new T[Other._Length])            {                for (size_t i = 0; i < Other._Length; i++)                {                    _Content[i] = Other._Content[i];                }            }            Span(const T *Array, size_t Size) : _Length(Size), _Content(new T[Size])            {                for (size_t i = 0; i < Size; i++)                {                    _Content[i] = Array[i];                }            }            Span(std::initializer_list<T> list) : _Length(list.size()), _Content(new T[list.size()])            {                size_t i = 0;                for (auto &item : list)                {                    _Content[i] = item;                    i++;                }            }            ~Span()            {                delete[] _Content;                _Content = nullptr;            }            inline T *Content()            {                return _Content;            }            inline const T *Content() const            {                return _Content;            }            inline size_t Length() const            {                return _Length;            }            T &operator[](const size_t &Index)            {                if (Index >= _Length)                    throw std::out_of_range("");                return _ElementAt(Index);            }            const T &operator[](const size_t &Index) const            {                if (Index >= _Length)                    throw std::out_of_range("");                return _ElementAt(Index);            }            Span &operator=(const Span &Other)            {                if (this != &Other)                {                    _Length = Other._Length;                    delete[] _Content;                    _Content = new T[_Length];                    for (size_t i = 0; i < _Length; i++)                    {                        _Content[i] = Other._Content[i];                    }                }                return *this;            }            Span &operator=(Span &&Other)            {                if (this != &Other)                {                    delete[] _Content;                    _Content = Other._Content;                    _Length = Other._Length;                    Other._Content = nullptr;                    Other._Length = 0;                }                return *this;            }        };        template <typename T>        class BQueue final        {        public:            // Constructors            BQueue() = default;            BQueue(size_t Size, bool Growable = true) : _Content(Size), _First(0), _Length(0), _Growable(Growable) {}            BQueue(std::initializer_list<T> list) : _Content(list), _First(0), _Length(list.size()), _Growable(true) {}            BQueue(const BQueue &Other) : _Content(Other._Content), _First(Other._First), _Length(Other._Length), _Growable(Other._Growable) {}            BQueue(BQueue &&Other) : _Content(Other._Content), _First(Other._First), _Length(Other._Length), _Growable(Other._Growable)            {                Other._First = 0;                Other._Length = 0;                Other._Growable = true;            }            // Operators            BQueue &operator=(const BQueue &Other)            {                if (this != &Other)                {                    _Content = Other._Content;                    _First = Other._First;                    _Length = Other._Length;                    _Growable = Other._Growable;                }                return *this;            }            BQueue &operator=(BQueue &&Other)            {                if (this != &Other)                {                    _Content = std::move(Other._Content);                    _First = std::move(Other._First);                    _Length = std::move(Other._Length);                    _Growable = std::move(Other._Growable);                    Other._First = 0;                    Other._Length = 0;                    Other.Growable = true;                }                return *this;            }            T &operator[](size_t Index)            {                if (Index >= _Length)                    throw std::out_of_range("Index out of range");                return _Content.Content()[(_First + Index) % Capacity()];            }            T const &operator[](size_t Index) const            {                if (Index >= _Length)                    throw std::out_of_range("Index out of range");                return _Content.Content()[(_First + Index) % Capacity()];            }            // Peroperties            size_t Capacity() const            {                return _Content.Length();            }            size_t Length() const            {                return _Length;            }            bool Growable() const            {                return _Growable;            }            T *Content()            {                return _Content.Content();            }            T const *Content() const            {                return _Content.Content();            }            inline bool IsWrapped() const            {                return _First + _Length > Capacity();            }            inline bool IsEmpty() noexcept { return _Length == 0; }            inline bool IsFull() noexcept { return _Length == Capacity(); }            inline size_t IsFree() noexcept { return Capacity() - _Length; }            // Helper functions            T &Head()            {                AssertNotEmpty();                return _Content.Content()[_First];            }            T const &Head() const            {                AssertNotEmpty();                return _Content.Content()[_First];            }            // Remove functionality            void Pop()            {                std::destroy_at(std::addressof(Head()));                --_Length;                _First = (_First + 1) % Capacity();            }        private:            Iterable::Span<T> _Content;            size_t _First = 0;            size_t _Length = 0;            bool _Growable = true;            inline void AssertNotEmpty()            {                if (IsEmpty())                    throw std::out_of_range("Instance is empty");            }        };    }}class Messenger{public:    int Id = -1;    Messenger() = default;    Messenger(size_t id) : Id(id)    {        std::cout << Id << " Constructed" << std::endl;    }    Messenger(Messenger &&Other) : Id(Other.Id)    {        Other.Id = -1;    }    Messenger(Messenger const &Other) : Id(Other.Id) {}    Messenger &operator=(Messenger &&Other)    {        Id = Other.Id;        Other.Id = -1;        return *this;    }    Messenger &operator=(Messenger const &Other)    {        Id = Other.Id;        return *this;    }    ~Messenger()    {        if (Id != -1)        {            std::cout << Id << " Destructed" << std::endl;            Id = -1;        }    }};using namespace Core;int main(int argc, char const *argv[]){    Iterable::BQueue<Messenger> Queue{1, 2};    Queue.Pop();    Queue.Pop();    std::cout << "Finished" << std::endl;    return 0;}

And here the output that i get:

1 Constructed2 Constructed1 Destructed2 DestructedFinished2 Destructed1 Destructed

As you can see, after printing Finished, nothing else must be printed.


Viewing all articles
Browse latest Browse all 22201

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>