【问题标题】:Segmentation fault when Using std::initializer_list<std::string> in Constructor在构造函数中使用 std::initializer_list<std::string> 时出现分段错误
【发布时间】:2021-03-15 04:48:41
【问题描述】:

您好,我想了解构造函数的工作原理,并阅读不同的示例。我有一个类构造函数,它接受一个 initializer_list,但它不断给出Segmentation fault。我拥有的文件如下:

  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. ma​​infile.cpp
int main() {
StrVec sv10 { "il1", "il2", "il3", "il4", "il5" };
return 0;
}

我的问题是我该如何解决这个问题,为什么我会收到这个Segmentation fault,这是什么意思,以便我以后可以避免它?

PS:我知道错误是由 StrVec(std::initializer_list&lt;std::string&gt; il); 构造函数引起的,因为如果我删除它并在 mainfile.cpp 中使用它,那么 Segmentation fault 就会消失。

【问题讨论】:

  • 请附上minimal reproducible example 以及您从调试器和地址清理器等工具中学到的东西。
  • 我知道错误是由于 StrVec(std::initializer_list&lt;std::string&gt; il); 构造函数,因为如果我删除它并在 mainfile.cpp 中使用它,那么分段错误就会消失
  • 好的,但我们甚至不知道构造函数除了调用push_back 之外还做了什么,而且我们自己也无法尝试。
  • StrVec(std::initializer_list&lt;std::string&gt; il); 只调用了一个函数push_back 而你没有提供你的实现
  • 我添加了 push_back() 成员。

标签: c++ c++11 segmentation-fault c++14


【解决方案1】:

[这里只是猜测,因为你没有显示正确的minimal reproducible example。]

你的类中有一组指针。

你的StrVec(std::initializer_list&lt;std::string&gt; il) 构造函数初始化这些指针,所以push_back 很可能会使用这些未初始化的指针,而你会有未定义的行为 em> 和崩溃。

您可以通过委托默认构造函数轻松地进行默认初始化:

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

话虽如此,std::initializer_list 将具有大小,这意味着您可以预先分配所需的确切数量的元素,然后复制它们,而不是在循环中调用 push_back

【讨论】:

  • 是的,这似乎修复了Segmentaion fault。因此,据我所知,现在这样说是否正确:“由于我们在类中有三个指针,并且我们没有为它们提供任何初始化,因此它们之前被默认初始化,这意味着它们具有未定义的行为。为了解决这个问题我们应该将工作委托给默认构造函数,或者我们可以在 StrVec::StrVec(std::initializer_list&lt;std::string&gt; il) 正文中初始化它们,例如 elements=first_free=cap=nullptr;"或者我们也可以成员初始化它们。我的上述说法正确吗?
  • @JasonLiam 是这样的。
  • 好吧,我试过StrVec::StrVec(std::initializer_list&lt;std::string&gt; il):elements(nullptr), first_free(nullptr), cap(nullptr){for(const auto &amp;s:il){push_back(s);}},这行得通。谢谢
猜你喜欢
  • 2014-09-21
  • 1970-01-01
  • 1970-01-01
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多