为啥当 T=std::string custom Vector C++ 时在 push_back(T&&) 上出现 SIGSEGV 错误

Posted

技术标签:

【中文标题】为啥当 T=std::string custom Vector C++ 时在 push_back(T&&) 上出现 SIGSEGV 错误【英文标题】:Why i get a SIGSEGV error on push_back(T&&) when T=std::string custom Vector C++为什么当 T=std::string custom Vector C++ 时在 push_back(T&&) 上出现 SIGSEGV 错误 【发布时间】:2021-05-16 17:12:20 【问题描述】:
#include <algorithm>
#include <utility>
#include <new>
#include <iostream>

template <typename T>
class Vector 
public:
    Vector();
    ~Vector();

    void push_back(const T& value);
    void push_back(T&& value);

    void clear();

    std::size_t size() const  return sz; 
    std::size_t capacity() const  return cap; 

    T& operator[](std::size_t i)  return data[i]; 
    const T& operator[](std::size_t i) const  return data[i]; 

private:
    T* data;
    std::size_t sz;
    std::size_t cap;

    void p_realloc(std::size_t n);
;

template <typename T>
Vector<T>::Vector()
    : sz, cap 10 

    data = (T*)::operator new(cap * sizeof(T));


template <typename T>
Vector<T>::~Vector() 
    clear();
    ::operator delete(data, sizeof(T) * cap);


template <typename T>
void Vector<T>::p_realloc(std::size_t n) 

    T* new_data = (T*)::operator new(n * sizeof(T));

    if (n < sz)
        sz = n;

    for (std::size_t i = 0; i < sz; ++i) 
        new_data[i] = std::move(data[i]);
        data[i].~T();
    

    ::operator delete(data, cap * sizeof(T));

    data = new_data;
    cap = n;


template <typename T>
void Vector<T>::clear() 
    for (std::size_t i = 0; i < sz; ++i)
        data[i].~T();
    sz = 0;



template <typename T>
void Vector<T>::push_back(const T& value) 
    if (sz >= cap)
        p_realloc(cap * 1.5);
    data[sz++] = value;


template <typename T>
void Vector<T>::push_back(T&& value) 
    if (sz >= cap)
        p_realloc(cap * 1.5);
    
    std::cout << "All good\n"; std::cin.get();

    data[sz++] = std::move(value);

我正在尝试创建 Vector 类的自定义实现。我已经做了一个,但它不使用 ::operator new 和 delete 以便不调用构造函数/析构函数。当 T=std::string 并且我尝试调用 push_back("test_string") 时,我得到一个错误,我不知道为什么。它不应该被隐式转换为 std::string 并因此 data[sz++] = std::move(value) 工作吗?

【问题讨论】:

void Vector&lt;T&gt;::push_back(T&amp;&amp; value) value 是转发引用,不一定是右值引用。 en.cppreference.com/w/cpp/language/… @RichardCritten 这不是转发参考。 T 是 Vector 的模板参数。 【参考方案1】:

错误不在使用 push_back(T&&) 中。原因在于data 指向未初始化的内存。

data[sz++] = value; 在未初始化的对象 T 上调用 T::operator=(const T&amp;)

data[sz++] = std::move(value); 在未初始化的对象 T 上调用 T::operator=(T&amp;&amp;)

您应该使用放置新的位置来修复push_back 中的分配data[sz++] =

/* data[sz++] = value; */            new (&data[sz++]) T(value);
/* data[sz++] = std::move(value); */ new (&data[sz++]) T(std::move(value));

【讨论】:

new (&amp;data[sz++]) T(value); AFAIK,这可能不安全。如果构造函数抛出异常,sz 会自增,向量将处于错误状态。 谢谢大家,我明白我的错误了。顺便说一句,我还需要在 p_realloc 函数中使用新的位置。我确保在构建后增加 sz :)

以上是关于为啥当 T=std::string custom Vector C++ 时在 push_back(T&&) 上出现 SIGSEGV 错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥'=='在std :: string上很慢?

为啥 g++ 不关心初始化列表分配给 (const std::string&) a (std::string)?和其他怪异[关闭]

为啥 std::string 零初始化为不确定值

为啥 std::string append 在 rval ref 上没有重载?

std::string 生成链接器错误—— const char* 不会。为啥?

为啥我可以在 std::map<std::string, int> 中使用 const char* 作为键