3

我一直在研究 Bjarne Stroustrup 的“C++ 编程语言”一书中的所有练习。

我遇到了一个让我难过的特定练习(E.8.4)
这是讨论标准库类中异常安全的附录.他说明了向量构造函数的一种可能实现,然后要求读者找出错误。提示表明它与析构函数有关(可能是双重释放?)但我只是没有看到他在追求什么.

据我所知,分配器可能会抛出 bad_alloc,从而终止 ctor。类似地,T 上的复制 ctor 可能会抛出 uninitialized_fill,这将破坏任何先前复制的元素并终止 ctor。如果那里有错误,那对我来说并不明显。

该练习的措辞如下:“在vector的构造函数(E.3.1)的'混乱'版本中找到错误并编写程序使其崩溃。提示:首先实现vector的析构函数。

这只是一个 1 分的练习,所以我一定遗漏了一些非常明显的东西。我认为这与抛出析构函数无关,因为在这种情况下所有赌注都没有了。也许在“space”和“last”字段中保持不变量存在问题?

我很想听听任何人的想法。

以下是相关代码:

template<class T, class A = std::allocator<T> >
class vector {
private:
    T* v;
    T* space;
    T* last;
    A alloc;

    void destroy_all();
public:
    typedef size_t size_type;

    explicit vector(size_type n, const T& val = T(), const A& = A());
    vector(const vector& a);
    vector& operator=(const vector& a);
    ~vector() { destroy_all(); alloc.deallocate(v, last-v); }
    size_type size() const { return space-v; }
    size_type capacity() const { return last-v; }
    void push_back(const T&);
};

template<class T, class A>
void vector<T,A>::destroy_all() {
    for(T* p = v; p != last; p++)
        alloc.destroy(p);
}

template<class T, class A>
vector<T,A>::vector(size_type n, const T& val, const A& a) : alloc(a) {
    v = alloc.allocate(n);
    try {
        std::uninitialized_fill(v, v + n, val);
        space = last = v + n;
    }
    catch(...) {
        alloc.deallocate(v, n);
        throw;
    }
}
4

2 回答 2

0

问题是 for 的构造函数T可以抛出,这意味着 this 可以抛出:

std::uninitialized_fill(v, v + n, val);

发生这种情况时,该子句会在不正确销毁任何可能已经构造的对象的catch(...)情况下释放内存。T

于 2012-09-05T03:23:34.690 回答
0

allocator::allocate可以扔std::bad_alloc。在这种情况下,您未初始化v,即使您从内存不足中恢复,您也会在销毁时出现段错误。

另一个问题是std::initialized_fill. 如果它抛出,你释放内部存储而不将数据指针标记为无效。析构函数将再次释放相同的内存。

于 2012-10-13T13:18:50.290 回答