瞬态复制构造函数的怪异

发布于 2025-01-04 20:38:45 字数 4559 浏览 0 评论 0原文

我在头文件中定义了这个类:

class E_IndexList {
public:
    E_UIntegerList* l;
    inline void *data() { // retrieve packed data: stride depends on type (range)
        return l->data();
    }
    inline void insert(unsigned value) {
        if (value > maxval[l->range]) {
            promote();
            insert(value);
        } else {
            l->push_back(value);
        }
    }
    inline size_t size() {
        return l->size();
    }
    inline unsigned long get(int index) {
        return l->get(index);
    }
    void promote() {
        if (l->range == E_UIntegerList::e_byte) {
            E_UShortList *new_short_list = new E_UShortList(*((E_UByteList*)l));
            delete l;
            l = new_short_list;
        } else if (l->range == E_UIntegerList::e_short) {
            E_UIntList *new_int_list = new E_UIntList(*((E_UShortList*)l));
            delete l;
            l = new_int_list;
        } else ASSERT(false);
    }
    // start off with bytes by default
    E_IndexList() {
        l = new E_UByteList;
    }
    E_IndexList(E_UIntegerList::int_bits range) {
        switch(range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList;
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList;
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList;
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    E_IndexList(const E_IndexList& cpy) { // copy ctor
        switch(cpy.l->range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList(((E_UByteList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList(((E_UShortList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList(((E_UShortList*)cpy.l)->list);
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    ~E_IndexList() {
        delete l;
    }
};

这里是它使用的其他一些类:

static const unsigned long maxval[] = {0xff,0xffff,0xffffffff};
class E_UIntegerList {
public:
    enum int_bits {e_byte = 0, e_short = 1, e_int = 2};
    virtual ~E_UIntegerList() {}
    int_bits range;
    virtual void push_back(int i) = 0;
    virtual void *data() = 0;
    virtual size_t size() = 0;
    virtual unsigned long get(int index) = 0;
};
struct E_UByteList:public E_UIntegerList {
    std::vector<unsigned char> list;
    E_UByteList() {
        range = e_byte;
    }
    E_UByteList(const std::vector<unsigned char>& copy) {
        list = copy;
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UShortList:public E_UIntegerList {
    std::vector<unsigned short> list;
    E_UShortList() {
        range = e_short;
    }
    E_UShortList(const std::vector<unsigned short>& copy) {
        list = copy;
    }
    E_UShortList(const E_UByteList& promotee) {
        range = e_short;
        list.assign(promotee.list.begin(),promotee.list.end()); // assignment should be compatible
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UIntList:public E_UIntegerList {
    std::vector<unsigned int> list;
    E_UIntList() {
        range = e_int;
    }
    E_UIntList(const std::vector<unsigned int>& copy) {
        list = copy;
    }
    E_UIntList(const E_UShortList& promotee) {
        range = e_int;
        list.assign(promotee.list.begin(),promotee.list.end());
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};

现在我使用这个类的方式是我有一个 std::vector我用作索引列表的容器。

奇怪的行为是,当我运行程序时,有时它没有问题,有时它断言为假。

所以这对我来说是一个很大的危险信号,因为正在发生一些非常可疑的事情。我很可能最终会放弃整个 E_IndexList 直到我开始研究游戏网络代码,这还有很长的路要走。但是,我想知道这里发生了什么事。

我拥有的每个 ctor 将范围设置为 E_UIntegerList 中枚举之外的有效值,那么该断言怎么会被触发呢?我无法开始解释为什么这种行为不一致。调用此代码的测试不是多线程的。

I've got this here class defined in a header file:

class E_IndexList {
public:
    E_UIntegerList* l;
    inline void *data() { // retrieve packed data: stride depends on type (range)
        return l->data();
    }
    inline void insert(unsigned value) {
        if (value > maxval[l->range]) {
            promote();
            insert(value);
        } else {
            l->push_back(value);
        }
    }
    inline size_t size() {
        return l->size();
    }
    inline unsigned long get(int index) {
        return l->get(index);
    }
    void promote() {
        if (l->range == E_UIntegerList::e_byte) {
            E_UShortList *new_short_list = new E_UShortList(*((E_UByteList*)l));
            delete l;
            l = new_short_list;
        } else if (l->range == E_UIntegerList::e_short) {
            E_UIntList *new_int_list = new E_UIntList(*((E_UShortList*)l));
            delete l;
            l = new_int_list;
        } else ASSERT(false);
    }
    // start off with bytes by default
    E_IndexList() {
        l = new E_UByteList;
    }
    E_IndexList(E_UIntegerList::int_bits range) {
        switch(range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList;
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList;
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList;
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    E_IndexList(const E_IndexList& cpy) { // copy ctor
        switch(cpy.l->range) {
        case E_UIntegerList::e_byte:
            l = new E_UByteList(((E_UByteList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_short:
            l = new E_UShortList(((E_UShortList*)cpy.l)->list);
            break;
        case E_UIntegerList::e_int:
            l = new E_UIntList(((E_UShortList*)cpy.l)->list);
            break;
        default:
            ASSERT(false);
            break;
        }
    }
    ~E_IndexList() {
        delete l;
    }
};

Here are some more classes it makes use of:

static const unsigned long maxval[] = {0xff,0xffff,0xffffffff};
class E_UIntegerList {
public:
    enum int_bits {e_byte = 0, e_short = 1, e_int = 2};
    virtual ~E_UIntegerList() {}
    int_bits range;
    virtual void push_back(int i) = 0;
    virtual void *data() = 0;
    virtual size_t size() = 0;
    virtual unsigned long get(int index) = 0;
};
struct E_UByteList:public E_UIntegerList {
    std::vector<unsigned char> list;
    E_UByteList() {
        range = e_byte;
    }
    E_UByteList(const std::vector<unsigned char>& copy) {
        list = copy;
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UShortList:public E_UIntegerList {
    std::vector<unsigned short> list;
    E_UShortList() {
        range = e_short;
    }
    E_UShortList(const std::vector<unsigned short>& copy) {
        list = copy;
    }
    E_UShortList(const E_UByteList& promotee) {
        range = e_short;
        list.assign(promotee.list.begin(),promotee.list.end()); // assignment should be compatible
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};
struct E_UIntList:public E_UIntegerList {
    std::vector<unsigned int> list;
    E_UIntList() {
        range = e_int;
    }
    E_UIntList(const std::vector<unsigned int>& copy) {
        list = copy;
    }
    E_UIntList(const E_UShortList& promotee) {
        range = e_int;
        list.assign(promotee.list.begin(),promotee.list.end());
    }
    inline void push_back(int i) {
        list.push_back(i);
    }
    inline void *data() { return list.data(); }
    inline size_t size() { return list.size(); }
    inline unsigned long get(int index) { return list[index]; }
};

Now the way that I use this class is I have a std::vector<E_IndexList> that I use as a container of index lists.

The strange behavior is that when I run the program sometimes it has no problems and sometimes it asserts false.

So this is a big red flag for me because something super fishy is going on. I will very likely end up abandoning the entire E_IndexList until I start working on game netcode which is a long ways off. But, I'd like to know what's going on here.

Every ctor I have sets the range to a valid value out of the enum in E_UIntegerList, so how could that assertion ever get tripped? And I can't begin to come up with an explanation of why the behavior is inconsistent. The test that calls this code is not multi-threaded.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小瓶盖 2025-01-11 20:38:45

您的 E_UByteList from-vector 构造函数未设置 range 值。

整个设计有点粗制滥造;您应该学习如何使用构造函数初始值设定项列表,并且我可能会为基类赋予一个受保护的构造函数,该构造函数设置 range 值,并且可以从派生构造函数的初始值设定项中调用该构造函数。

Your E_UByteList from-vector constructor does not set the range value.

The entire design is a bit shoddy; you should learn how to use constructor initializer lists, and I would probably endow the base class with a protected constructor that sets the range value and which can be invoked from within the derived constructors' initializers.

怪异←思 2025-01-11 20:38:45

您没有定义赋值运算符。请参阅三规则

You didn't define an assignment operator. See rule of three.

沫尐诺 2025-01-11 20:38:45

您的构造函数(例如此构造函数):

E_UByteList(const std::vector<unsigned char>& copy) {
    list = copy;
}

不要从父 E_UIntegerList 类初始化 range

Your constructors such as this one:

E_UByteList(const std::vector<unsigned char>& copy) {
    list = copy;
}

do not initialise range from the parent E_UIntegerList class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文