1

I have one or two files that seems to be using boost::optional. However the error thrown is very unfriendly. I just don't know where to start looking to solve this error. It isn't pointing to a line of code that I have. Instead it is starting at optional.hpp which is a boost header file and this is the only message thrown.

/usr/include/boost/optional/optional.hpp:1191: boost::optional<T>::reference_type boost::optional<T>::get() 
[with T = tev::events::EventItemCategory; boost::optional<T>::reference_type = tev::events::EventItemCategory&]: Assertion `this->is_initialized()' failed.

This is what I got from gdb:

(gdb) c 
Continuing. 
/usr/include/boost/optional/optional.hpp:1191: boost::optional<T>::reference_type boost::optional<T>::get() [with T = tev::events::EventItemCategory; boost::optional<T>::reference_type = tev::events::EventItemCategory&]: 
Assertion `this->is_initialized()' failed.
Program received signal SIGABRT, Aborted. 
0x0000007f9c105064 in ?? () 
(gdb) bt 
#0 0x0000007f9c105064 in ?? () 
#1 0x0000007f9c13c898 in ?? () 
Backtrace stopped: previous frame inner to this frame (corrupt stack?) 
(gdb) q

valgrind output

==32083== Warning: invalid file descriptor -1 in syscall close()                                                                                                                                          
==32083==    at 0x4C8A574: close (in /lib/libpthread-2.25.so)                                                                                                                                             
==32083==    by 0x4A24123: setFilename(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /opt/ad/lib/libconfiguration.so)      
==32083==    by 0x4A25A4F: (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char
==32083==    by 0x4A31FFB: Configuration() (in /opt/ad/lib/libconfiguration.so)                                                                                       
==32083==    by 0x5484DF: GetInstance (Singleton.h:80)                                                                                                                                                  
==32083==    by 0x5484DF: RecordingFactory::RecordingFactory() (RecordingFactory.cpp:18)                                                                                                          
==32083==    by 0x56D3C7: GetInstance (Singleton.h:39)                                                                                                                                                    
==32083==    by 0x56D3C7: Service(bool&, std::shared_ptr<tev::events::EventServiceResource> const&, int) (Service.cpp:59)                                                                   
==32083==    by 0x4D391B: ABCService (ABC.h:38)                                                                                                                                                       
==32083==    by 0x4D391B: void create_service_thread<trc::Service>(std::vector<unsigned long, std::allocator<unsigned long> >&, std::vector<ABCServiceBase*, std::allocator<ABCServiceBase*> >&, bool&, 
==32083==    by 0x4B3DF7: main (ABC.cpp:140)   
/arm/release/usr/include/boost/optional/optional.hpp:1191: boost::optional<T>::reference_type boost::optional<T>::get() 
[with T = tev::events::EventItemCategory; boost::optional<T>::reference_type = tev::events::EventItemCategory&]: Assertion `this->is_initialized()' failed.
==32083==                                                            
==32083== Process terminating with default action of signal 6 (SIGABRT)
==32083==    at 0x63BA064: raise (in /lib/libc-2.25.so)             
==32083==                                                     
==32083== HEAP SUMMARY:                                       
==32083==     in use at exit: 8,217,174 bytes in 9,658 blocks           
==32083==   total heap usage: 59,869 allocs, 50,211 frees, 13,722,597 bytes allocated
==32083==                                                               
==32083== Searching for pointers to 9,658 not-freed blocks                                                               
==32083== Checked 104,459,168 bytes                                                                                      
==32083==                                                                                                                
==32083== 8 bytes in 1 blocks are still reachable in loss record 1 of 2,795                                              
==32083==

MSVP

#include<iostream>
#include <boost/optional.hpp>
using namespace std;

class Myclass
{
public:
    int a;
};

boost::optional<Myclass> func(int a)
{
    boost::optional<Myclass> value;
    if(a == 0)
    {

            /* This results in the same runtime error discussed in the question */
            value->a = {200};

           /* The following #if 0 , if enabled would remove the error */
#if 0 
            Myclass c;
            c.a = 200;
            value = c;
#endif

    }

    return value;
}

int main(int argc, char **argv)
{
    boost::optional<Myclass> v = func(0);

    if(v)
        std::cout << v -> a << std::endl;
    else
        std::cout << "Uninitialized" << std::endl;
    std::cin.get();

    return 0;
}
badri
  • 575
  • 2
  • 8
  • 22
  • 3
    Where is the [mcve]? – R Sahu Aug 10 '21 at 22:11
  • I don't know where to start to even provide a Minimal reproducible example ! All I know is that the huge chunk of code is erroring out with this message that is in boost optional. i suppose the answer is that there are bits in C++11 which are very unhelpful ! – badri Aug 10 '21 at 22:13
  • @badri read the instructions on the Minimal Reproducible Example link, it includes advice of where to even start. Section titled "Minimal" – M.M Aug 10 '21 at 22:14
  • 2
    `boost:optional::get()` returns a *reference* to the value it is holding. If there is no value stored, `get()` raises an assert. So, somewhere, there is code that is trying to access an `EventItemCategory` from an `optional` that is not holding an `EventItemCategory`. You are just going to have to debug the code to find it. – Remy Lebeau Aug 10 '21 at 22:14
  • @RemyLebeau - Does it mean that the error is within the class EventItemCategory ? – badri Aug 10 '21 at 22:17
  • @jxh - this is all that i got even from gdb. (gdb) c Continuing. /usr/include/boost/optional/optional.hpp:1191: boost::optional::reference_type boost::optional::get() [with T = tev::events::EventItemCategory; boost::optional::reference_type = tev::events::EventItemCategory&]: Assertion `this->is_initialized()' failed. Program received signal SIGABRT, Aborted. 0x0000007f9c105064 in ?? () (gdb) bt #0 0x0000007f9c105064 in ?? () #1 0x0000007f9c13c898 in ?? () Backtrace stopped: previous frame inner to this frame (corrupt stack?) (gdb) q – badri Aug 10 '21 at 22:18
  • 2
    @badri no, the error has nothing to do with `EventItemCategory` itself. The error is merely stating that the `optional` in question is declared to hold an `EventItemCategory`. – Remy Lebeau Aug 10 '21 at 22:19
  • That is a good start. Did you compile with debugging symbols included? (usually `-g`) – jxh Aug 10 '21 at 22:19
  • yes @jxh. It was built with debugging symbols. – badri Aug 10 '21 at 22:20
  • 1
    Please clarify whether this is a compilation error or a runtime error -- the title suggests a compilation error but the comments you have posted suggest runtime – M.M Aug 10 '21 at 22:20
  • sorry @M.M. Didn't realize that. fixed itnow – badri Aug 10 '21 at 22:21
  • Thanks Remy. I think i got you now. I just have to search for all the optional variables (holding EventItemCategory) in use and check if it is initialized or not. – badri Aug 10 '21 at 22:22
  • 2
    I think it would be worth the effort to find out why you are not getting a useful backtrace from `gdb`. – jxh Aug 10 '21 at 22:26
  • Is the code in a signal handler or something like that? – M.M Aug 10 '21 at 22:27
  • Where was your breakpoint? – jxh Aug 10 '21 at 22:33
  • Did you try running your program with `valgrind`? – jxh Aug 10 '21 at 22:36
  • 1
    _I think it would be worth the effort to find out why you are not getting a useful backtrace from gdb_ Yes. Perhaps compile with optimisations disabled. – Paul Sanders Aug 10 '21 at 23:52
  • @RemyLebeau - Am I right in my understanding. An boost optional variable means that it is optional for it to contain (and return) a value. Is the failure happening because a check for is_initialized() must have been carried out ? I am trying code walkthrough since i am not finding any useful info from gdb or valgrind. Even tried Paul sanders idea of disabling optimisations. – badri Aug 11 '21 at 12:17
  • What is the valgrind output? – jxh Aug 11 '21 at 14:38
  • @jxh - Do you see how suddenly out of the blue that line is spewed out. There is nothing before it, nothing related that is after it. This was on a build with minimalistic gdb and no optimisations ( -g -UNDEBUG ) – badri Aug 11 '21 at 15:00
  • same even with gdb, I let it run and tried a backtrace. – badri Aug 11 '21 at 15:02
  • I see there was a `close()` call on an invalid descriptor, so you might want to track that down. All the warnings `valgrind` shows you are potential hints that the code needs fixing. Fixing the warnings might lead to the assertion failure line going away, or more obvious where it is originating from. Since your code is multi-threaded, it is possible you have an object that is being destructed twice inadvertently, but that is just a guess. – jxh Aug 11 '21 at 15:19
  • Not that it is impossible for single threaded code to do double deletion, it is a little easier in multi-threaded code. Like, when an object is shared between multiple threads, and each assumes the responsibility of deletion. – jxh Aug 11 '21 at 15:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/235897/discussion-between-badri-and-jxh). – badri Aug 11 '21 at 16:21
  • `value` is empty at this point, therefore `operator->()` asserts. What's the problem? – n. m. could be an AI Aug 12 '21 at 09:17
  • @n.1.8e9-where's-my-sharem. - boost::optional value; would this not invoke any constructor ? This syntax is confusing me. If it was Myclass value, that would mean value is an object for the class Myclass and therefore the default constructor would be called. what happens here – badri Aug 12 '21 at 09:25
  • i think i got my answer here - https://stackoverflow.com/questions/22227839/how-to-use-boostoptional . I will search my code for the faulting portion. – badri Aug 12 '21 at 09:44

1 Answers1

1

The use of -> operator is only valid if the optional is initialized. Boost decided to trigger an assertion failure and abort.

Suppose that optional allowed you to modify a single field like you attempted to do. Then it would not be able to say whether or not the object is fully initialized and should be destructed. So, the API makes you fully initialize the object held by the optional, so that when the optional destructs, it knows whether or not destruction of the held object is required.

If you want your optional to be initialized with a default constructed instance, then you can make that explicit in your code.

    boost::optional<Myclass> value = Myclass();
    value->a = 200;

For your use case, a more straight forward approach is to simply return the class instance, and have that initialize the optional return value, and return boost::none to signal that the optional was not initialized.

    Myclass c;
    if(a == 0)
    {
        c.a = 200;
        return c;
    }
    return boost::none;
jxh
  • 69,070
  • 8
  • 110
  • 193