使用引用参数传递引用意外行为

时间:2014-12-01 00:58:56

标签: c++ function reference call

在尝试将基于for循环的范围内的const引用值传递给a时出现问题 采用const引用值的函数。查看基于循环的范围内的通知,看看我在谈论什么。我的实施' unordered_vector'似乎不是一个问题。这是我最初的想法,因为它在函数外正确打印。为什么这会失败?如果我通过价值,它就有效,所以我在这里有点困惑。看起来它引用的引用似乎不是正确的行为。

void println(const vec3& p)
{
    std::cout << '<' << p.x << ',' << p.y << ',' << p.z << '>' << std::endl;
}

void printlnvalue(vec3 p)
{
    std::cout << '<' << p.x << ',' << p.y << ',' << p.z << '>' << std::endl;
}

const int vector_length = 7;

int _tmain(int argc, _TCHAR* argv[])
{
    unordered_vector<vec3> vectors(vector_length);

    for (int i = 0; i < vector_length; ++i)
    {
        vectors.push_back(vec3(0.1f*i, 0.2f*i, 0.3f*i));
    }

    for (const auto& i : vectors)
    {
        //Prints correctly
        printlnvalue(i);
        //Function that does same thing but doesn't print correctly.
        println(i);
    }

    return 0;
}

输出

<0,0,0>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.1,0.2,0.3>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.2,0.4,0.6>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.3,0.6,0.9>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.4,0.8,1.2>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.5,1,1.5>
<8.68805E-044,2.66467E-038,4.12969E-039>
<0.6,1.2,1.8>
<8.68805E-044,2.66467E-038,4.12969E-039>

unordered_vector声明

template<typename T>
class unordered_vector
{
private:
    T* m_data;
    size_t m_size;
    size_t m_capacity;
public:
    typedef unordered_vector_iterator<T> iterator;
    typedef unordered_vector_iterator<T> const const_iterator;
    typedef ptrdiff_t difference_type;
    typedef size_t size_type;
    typedef T value_type;
    typedef T* pointer;
    typedef T& reference;

    size_t size(void) const;
    size_t capacity(void) const;
    bool empty(void) const;

    void resize(size_t count);
    void reserve(size_t count);

    void push_back(const T& val);

    const_iterator begin(void) const;
    const_iterator end(void) const;

    void shrink_to_fit(void);

    void erase(size_t i);
    void erase(const T& val);
    void erase_all(const T& val);

    T& operator[](size_t i);
    T operator[](size_t i) const;
    unordered_vector& operator=(const unordered_vector& copy);
    unordered_vector& operator=(unordered_vector&& mov);

    unordered_vector(void);
    unordered_vector(size_t _size);
    unordered_vector(unordered_vector& copy);
    unordered_vector(unordered_vector&& mov);
    ~unordered_vector(void);
};

unordered_vector定义

template<typename T>
/*
    Returns the number of active units within
    the unordered_vector.
*/
size_t unordered_vector<T>::size(void) const 
{
    return m_size; 
}

template<typename T>
/*
    Returns the potential size of the vector
    before it would have to resize.
*/
size_t unordered_vector<T>::capacity(void) const { return m_capacity; }

template<typename T>
/*
    Returns true if no active units are within the vector. size() == 0
*/
bool unordered_vector<T>::empty(void) const 
{
    return m_size == 0; 
}

template<typename T>
/*
    This resizes the vector where anything between the parameter and 
    size is part of the capacity.
*/
void unordered_vector<T>::reserve(size_t count)
{
    if (count > m_capacity)
    {
        //Set capacity to new value
        m_capacity = count;
        //Make new array
        T* new_ptr = static_cast<T*>(malloc(sizeof(T)*m_capacity));
        //Copy preexisting data byte for byte
        if (m_data != nullptr)
        {
            //Copy data from previous buffer to new buffer
            memcpy(new_ptr, m_data, sizeof(T)*m_size);
            //Delete previous buffer
            free(m_data);
        }
        //Set pointer to the new array
        m_data = new_ptr;
    }
}

template<typename T>
/*
    Will resize the vector but each of the units is
    active if the buffer is increased. If the size
    is reduced then items at the end are truncated.
*/
void unordered_vector<T>::resize(size_t count)
{
    if (count > m_capacity)
    {
        //Set capacity to new value
        m_capacity = count;
        //Make new array
        T* new_ptr = static_cast<T*>(malloc(sizeof(T)*m_capacity));
        //Copy preexisting data byte for byte
        if (m_data != nullptr)
        {
            //Copy data from previous buffer to new buffer
            memcpy(new_ptr, m_data, sizeof(T)*m_size);
            //Delete previous buffer
            free(m_data);
        }
        //Set pointer to the new array
        m_data = new_ptr;
        //Make default values at each location
        for (; m_size < count; ++m_size)
        {

        }
    }
    else if (count < m_capacity)
    {
        if (count < m_size) m_size = count;
        //Set capacity to new value
        m_capacity = count;
        //Make new array
        T* new_ptr = static_cast<T*>(malloc(sizeof(T)*m_capacity));
        //Copy preexisting data byte for byte
        if (m_data != nullptr)
        {
            //Copy data from previous buffer to new buffer
            memcpy(new_ptr, m_data, sizeof(T)*m_size);
            //Delete previous buffer
            free(m_data);
        }
        //Set pointer to the new array
        m_data = new_ptr;
    }
}

template<typename T>
/*
    Shrinks capacity so capacity() == size().
*/
void unordered_vector<T>::shrink_to_fit(void)
{
    if (m_size != m_capacity && m_data != nullptr)
    {
        m_capacity = m_size;
        //Make new array
        T* new_ptr = static_cast<T*>(malloc(sizeof(T)*m_capacity));
        //Copy preexisting data byte for byte
        memcpy(new_ptr, m_data, sizeof(T)*m_size);
        //Delete previous buffer
        if (m_data != nullptr)
            free(m_data);
        //Set pointer to the new array
        m_data = new_ptr;
    }
}

template<typename T>
/*
    Will copy a value into the next open space of the vector.
    If there isn't room for an additional item it will resize
    the vector to accomadate it.
*/
void unordered_vector<T>::push_back(const T& val)
{
    //If we don't have any more room we need
    //to resize the array
    if (m_size == m_capacity)
    {
        m_capacity = m_capacity == 0 ? 8 : m_capacity * 2;
        //Make new array
        T* new_ptr = static_cast<T*>(malloc(sizeof(T)*m_capacity));
        if (m_data != nullptr)
        {
            //Copy preexisting data byte for byte
            memcpy(new_ptr, m_data, sizeof(T)*m_size);
            //Delete previous buffer
            free(m_data);
        }
        //Set pointer to the new array
        m_data = new_ptr;
    }

    m_data[m_size++] = val;
}

template<typename T>
/*
    Random accessor for writing to array.
*/
T& unordered_vector<T>::operator[](size_t i)
{
    assert(i >= 0 && i < m_size);
    return m_data[i];
}

template<typename T>
/*
    Random accessor for reading from array.
*/
T unordered_vector<T>::operator[](size_t i) const
{
    assert(i >= 0 && i < m_size);
    return m_data[i];
}

template<typename T>
/*
    Constant time erase. It reorders the vector
    internally to allow this.
*/
void unordered_vector<T>::erase(size_t i)
{
    assert(i >= 0 && i < m_size);

    if (i == m_size - 1)
        m_size -= 1;
    else
    {
        m_data[i] = m_data[m_size - 1];
        m_size -= 1;
    }
}

template<typename T>
/*
    Will remove the first value that matches 
    val if it exists. In the event no value is
    found the request is ignored.
*/
void unordered_vector<T>::erase(const T& val)
{
    for (size_t i = 0; i < m_size; ++i)
    {
        if (m_data[i] == val)
        {
            if (i == m_size - 1)
                m_size -= 1;
            else
            {
                m_data[i] = m_data[m_size - 1];
                m_size -= 1;
            }

            break;
        }
    }
}

template<typename T>
/*
    Will remove all values that match the parameter.
    If no items match the parameter then the request
    is ignored.
*/
void unordered_vector<T>::erase_all(const T& val)
{
    for (size_t i = 0; i < m_size; ++i)
    {
        if (m_data[i] == val)
        {
            if (i == m_size - 1)
                m_size -= 1;
            else
            {
                m_data[i] = m_data[m_size - 1];
                m_size -= 1;
                //Haven't checked the back yet
                //so we need to recheck i
                i--;
            }
        }
    }
}

template<typename T>
/*
    Initializes the vector with 0 capacity.
*/
unordered_vector<T>::unordered_vector(void)
    : m_data(nullptr), m_size(0), m_capacity(0) {}

template<typename T>
/*
    Initializes the vector with a capacity() equal to
    the parameter.
*/
unordered_vector<T>::unordered_vector(size_t count)
    : m_data(nullptr), m_size(0), m_capacity(0)
{
    reserve(count);
}

template<typename T>
/*
    Will copy data from another unordered_vector.
*/
unordered_vector<T>::unordered_vector(unordered_vector<T>& vector)
{
    if (vector.m_capacity > 0)
    {
        m_data = malloc(sizeof(T)*vector.m_capacity);

        if (vector.m_size > 0)
        memcpy(m_data, vector.m_data, sizeof(T)*vector.m_size);
    }

    m_capacity = vector.m_capacity;
    m_size = vector.m_size;
}

template<typename T>
/*
    Move constructor to effeciently transfer data between
    a temporary and another unordered_vector.
*/
unordered_vector<T>::unordered_vector(unordered_vector<T>&& mov)
{
    m_data = mov.m_data;
    m_capacity = mov.m_capacity;
    m_size = mov.m_size;
    mov.m_data = nullptr;
}

template<typename T>
/*
    Destructor that deallocates memory
    if any was allocated. Will not deallocate
    memory if move semantic was invoked.
*/
unordered_vector<T>::~unordered_vector(void)
{
    if (m_data != nullptr)
    {
        free(m_data);
        m_data = nullptr;
    }

    m_size = 0;
    m_capacity = 0;
}

template<typename T>
unordered_vector<T>& unordered_vector<T>::operator=(const unordered_vector<T>& copy)
{
    if (m_data != nullptr)
    {
        free(m_data);
        m_data = nullptr;
    }

    if (copy.m_capacity > 0)
    {
        m_data = malloc(sizeof(T)*copy.capacity());

        if (copy.m_size > 0)
            memcpy(m_data, copy.m_data, sizeof(T)*copy.m_size)
    }

    m_capacity = copy.m_capacity;
    m_size = copy.m_size;

    return *this;
}

template<typename T>
unordered_vector<T>& unordered_vector<T>::operator=(unordered_vector<T>&& mov)
{
    if (m_data != nullptr)
        free(m_data);

    m_data = mov.m_data;
    m_capacity = mov.m_capacity;
    m_size = mov.m_size;
    mov.m_data = nullptr;
}

template<typename T>
unordered_vector_iterator<T> const unordered_vector<T>::begin(void) const
{
    return unordered_vector_iterator<T>(this, 0);
}

template<typename T>
unordered_vector_iterator<T> const  unordered_vector<T>::end(void) const
{
    return unordered_vector_iterator<T>(this, m_size);
}

迭代器声明

template<typename T>
class unordered_vector_iterator
{
private:
    const unordered_vector<T>* const m_container;
    size_t m_index;
public:
    unordered_vector_iterator& operator++(void);
    unordered_vector_iterator& operator++(int);
    unordered_vector_iterator& operator--(void);
    unordered_vector_iterator& operator--(int);
    T& operator*(void) const;
    T& operator->(void) const;
    bool operator==(const unordered_vector_iterator& iter) const;
    bool operator!=(const unordered_vector_iterator& iter) const;
    unordered_vector_iterator(const unordered_vector<T>* const container, size_t index)
        : m_container(container), m_index(index) {}
};

迭代器定义

template<typename T>
bool unordered_vector_iterator<T>::operator==(const unordered_vector_iterator<T>& iter) const
{
    return iter.m_index == m_index && iter.m_container == m_container;
}

template<typename T>
bool unordered_vector_iterator<T>::operator!=(const unordered_vector_iterator<T>& iter) const
{
    return iter.m_index != m_index || iter.m_container != m_container;
}

template<typename T>
unordered_vector_iterator<T>&  unordered_vector_iterator<T>::operator++(void)
{
    ++m_index;
    return *this;
}

template<typename T>
unordered_vector_iterator<T>&  unordered_vector_iterator<T>::operator++(int)
{
    ++m_index;
    return *this;
}

template<typename T>
unordered_vector_iterator<T>&  unordered_vector_iterator<T>::operator--(void)
{
    --m_index;
    return *this;
}

template<typename T>
unordered_vector_iterator<T>&  unordered_vector_iterator<T>::operator--(int)
{
    --m_index;
    return *this;
}

template<typename T>
T& unordered_vector_iterator<T>::operator*(void) const
{
    return (*m_container)[m_index];
}

template<typename T>
T& unordered_vector_iterator<T>::operator->(void) const
{
    return (*m_container)[m_index];
}

vec3声明

struct vec3
{
public:
    float x, y, z;
    //vector functions
    void  normalize(void);
    float magnitude(void) const;
    float magnitudeSq(void) const;

    bool operator==(vec3 o) const;
    bool operator!=(vec3 o) const;
    //Constructors
    vec3(float _x, float _y, float _z)
        : x(_x), y(_y), z(_z) {}
    vec3(float s)
        : x(s), y(s), z(s) {}
    vec3() 
    : x(0.f), y(0.f), z(0.f) {}
};

2 个答案:

答案 0 :(得分:0)

您可能需要在unordered_vector中声明另一个运算符才能返回const T&。这就是它在STL vector类中声明的方式:

typedef const_reference const T&;
const_reference operator[](size_t idx) const;

答案 1 :(得分:0)

代码的问题是const方法不返回引用值。

此外,为了使代码工作,由于某种原因,它必须返回非常量引用值。这不是一个很好的答案,但现在通过将const索引运算符更改为此可以完美地运行。

template<typename T>
/*
    Random accessor for reading from array.
*/
T& unordered_vector<T>::operator[](size_t i) const
{
    assert(i >= 0 && i < m_size);
    return m_data[i];
}