简体   繁体   English

构造函数中的函数重载导致引用错误

[英]Overloaded function inside constructor causing deferencing error

While I am aware this is a stupid idea, I wanted to see if I could use a single class for both container and non-container types. 虽然我知道这是一个愚蠢的主意,但我想看看是否可以对容器和非容器类型使用单个类。 First, I copy-pasted code from this question. 首先,我从这个问题中复制粘贴了代码

Then I have two helper functions: one to determine the type of the member functions variables (whether or not T has the member value_type ) and the other to determine the return value of operator * . 然后,我有两个帮助函数:一个用于确定成员 函数 变量的类型( T是否具有成员value_type ),另一个用于确定operator *的返回值。

template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::value_type>::type
proxy_func_op() {

}

template <typename T>
typename std::enable_if<!HasValueType<T>::value, T>::type
proxy_func_op() {

}

template <typename T>
typename std::enable_if<HasValueType<T>::value, typename T::const_iterator>::type
proxy_func_mem() {
}

template <typename T>
typename std::enable_if<!HasValueType<T>::value, T*>::type
proxy_func_mem() {
}

And my class looks like this: 我的课看起来像这样:

template<typename T>
class MyIterator {

cur should be a pointer to T instead of a const_iterator if T does not have the value_type member. 如果T没有value_type成员,则cur应该是指向T的指针,而不是const_iterator If this is the case, begin and end are unused. 在这种情况下,开始和结束均未使用。

    decltype(proxy_func_mem<T>()) begin;
    decltype(proxy_func_mem<T>()) end;
    decltype(proxy_func_mem<T>()) cur;
public:

That is the logic of my init function here. 这就是我的init函数的逻辑。

    template <typename U = T>
    typename std::enable_if<HasValueType<U>::value, void>::type 
    init(U t) {
        static_assert(std::is_same<typename T::const_iterator, 
            decltype(proxy_func_mem<U>())>::value, 
            "Make sure correct function is called.");
        begin = t.begin();
        end = t.end();
        cur = begin;
    }

    template <typename U = T>
    typename std::enable_if<!HasValueType<U>::value, void>::type 
    init(U t) {
        static_assert(!std::is_same<typename T::const_iterator, 
        decltype(proxy_func_mem<U>())>::value, 
        "Make sure correct function is called.");
        cur = &t;
    }

I've narrowed the problem down to this one line. 我已将问题缩小到这一行。 If I remove init<T>(t) and copy-paste the contents of the first overload directly, I get proper results. 如果删除init<T>(t)并直接复制粘贴第一个重载的内容,则将得到正确的结果。 Otherwise, I get incorrect results. 否则,我会得到不正确的结果。

    explicit MyIterator(const T& t) {
        init<T>(t);
    }

    MyIterator& operator++() {
        static_assert(HasValueType<T>::value, "You cannot use this operator for non-containers.");
        if (cur + 1 != end)
            cur++;
        return *this;
    }

    decltype(proxy_func_op<T>()) operator *() {
        return *cur;
    }
};

For example, the incorrect output is: 例如,错误的输出是:

0
0
3
4
5
h
i

It seems to be calling the correct function. 它似乎正在调用正确的函数。 What is the problem? 问题是什么?

Edit 编辑

For some reason, changing the function signature to init(const U& t) { fixes the problem. 由于某种原因,将函数签名更改为init(const U& t) {可解决此问题。 Can anyone explain why? 谁能解释为什么?

The Code 编码


Valgrind error: Valgrind错误:

==4117== Invalid read of size 4
==4117==    at 0x401270: MyIterator<std::vector<int, std::allocator<int> > >::operator*() (main.cpp:78)
==4117==    by 0x400E8A: main (main.cpp:87)
==4117==  Address 0x514d0a0 is 0 bytes inside a block of size 20 free'd
==4117==    at 0x4A05FD6: operator delete(void*) (vg_replace_malloc.c:480)
==4117==    by 0x401CC5: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:110)
==4117==    by 0x401999: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:174)
==4117==    by 0x4014A4: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:160)
==4117==    by 0x4011A0: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:416)
==4117==    by 0x401209: MyIterator<std::vector<int, std::allocator<int> > >::MyIterator(std::vector<int, std::allocator<int> > const&) (main.cpp:67)
==4117==    by 0x400E75: main (main.cpp:85)

Valgrind detects no errors when I don't call init<T>(t) . 当我不调用init<T>(t)时,Valgrind不会检测到错误。


init accepting its parameter by value means that it is a copy of the original object. init通过值接受其参数意味着它是原始对象的副本。 You are storing iterators from that copy, which is destroyed when init returns. 您正在存储该副本中的迭代器,当init返回时该迭代器将被销毁。 Destroying a container invalidates its iterators, so dereferencing those iterators has undefined behavior. 销毁容器会使其迭代器无效,因此取消引用这些迭代器具有未定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM