0

Hi i am trying to understand how constructors work and so reading different examples. I have a class constructor that takes an initializer_list but it keeps giving Segmentation fault. The files that i have are as follows:

  1. strvec.h
class StrVec {
public:
    StrVec(): elements(nullptr), first_free(nullptr), cap(nullptr) {

    }
    StrVec(const StrVec&);
    StrVec(std::initializer_list<std::string> il);
    StrVec &operator=(const StrVec&);
    ~StrVec();
    void push_back(const std::string&);
    void pop_back();
    void reserve(std::size_t);
    void resize(std::size_t, const std::string& = std::string());
    bool empty() const {
        return begin() == end();
    }
    
    
    std::size_t size() const {
        return first_free - elements;
    }
    std::size_t capacity() const{
        return cap - elements;
    }
    std::string *begin() const {
        return elements;
    }
    std::string *end() const {
        return first_free;
    }

    
private:
    static std::allocator<std::string> alloc;
    void chk_n_alloc() {
        if (size() == capacity()){
            reallocate();
        }
    }
    std::pair<std::string*, std::string*> alloc_n_copy(const std::string*, const std::string*);
    void free();
    void reallocate();

    std::string *elements;
    std::string *first_free;
    std::string *cap;
};
  1. strvec.cpp
StrVec::StrVec(const StrVec &s){
    auto newdata = alloc_n_copy(s.begin(), s.end());
    elements     = newdata.first;
    first_free   = cap = newdata.second;
}

StrVec::StrVec(std::initializer_list<std::string> il){
    for(const auto &s:il){
        push_back(s);
    }
}
std::pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string *b, const std::string *e){
    auto data = alloc.allocate(e - b);
    return {data, uninitialized_copy(b, e, data)};
}
void StrVec::push_back(const std::string& s){
    chk_n_alloc();
    alloc.construct(first_free++, s);
}
  1. mainfile.cpp
int main() {
StrVec sv10 { "il1", "il2", "il3", "il4", "il5" };
return 0;
}

My question is how can i resolve this issue and why am i getting this Segmentation fault and what does it mean so that i can avoid it in the future?

PS: I know that the error is due to the StrVec(std::initializer_list<std::string> il); constructor since if i remove this and its use in the mainfile.cpp then Segmentation fault goes away.

5
  • Please include a minimal reproducible example as well as what you've learned from tools such as your debugger and address sanitizer. Commented Mar 15, 2021 at 4:50
  • I know that the error is due to the StrVec(std::initializer_list<std::string> il); constructor since if i remove this and its use in the mainfile.cpp then Segmentation fault goes away Commented Mar 15, 2021 at 4:53
  • Okay, but we don't even know what that constructor does beyond calling push_back and there's no way we can try this ourselves. Commented Mar 15, 2021 at 4:57
  • StrVec(std::initializer_list<std::string> il); calls only one function push_back and you didn't provide your implementation for it Commented Mar 15, 2021 at 4:59
  • I have added the push_back() member. Commented Mar 15, 2021 at 4:59

1 Answer 1

1

[Just guessing here since you don't show a proper minimal reproducible example.]

You have a set of pointers in your class.

Your StrVec(std::initializer_list<std::string> il) constructor does not initialize these pointers, so push_back will most likely use these uninitialized pointers and you will have undefined behavior and the crash.

You can easily do the default initialization by delegating it to the default constructor:

StrVec::StrVec(std::initializer_list<std::string> il)
    : StrVec()  // Delegte default initialization
{
    for(const auto &s:il){
        push_back(s);
    }
}

With that said, the std::initializer_list will have a size, which means you can pre-allocate the exact number of elements needed, and then copy them instead of calling push_back in a loop.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes that seems to fix the Segmentaion fault. So as i understand it now is it correct to say that : "Since we have three pointer in the class and we did not provided any intialization for those so they were being default initialized before which means they had undefinied behavior. In order to solve that we should either delegate the work to default constructor or we can value initialize them inside the StrVec::StrVec(std::initializer_list<std::string> il) body like elements=first_free=cap=nullptr;" or we can also member initialize them. Is my above statement correct?
@JasonLiam Something like that yes.
Ok i tried StrVec::StrVec(std::initializer_list<std::string> il):elements(nullptr), first_free(nullptr), cap(nullptr){for(const auto &s:il){push_back(s);}} and this works . Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.