c++ printf和std::cout在尝试打印出从迭代器获得的std::vector内部的结构成员时表现不同

4si2a6ki  于 2023-01-15  发布在  其他
关注(0)|答案(1)|浏览(179)

我正在学习C++迭代器。我有一个奇怪的bug,当我试图从迭代器中获取一个结构的成员时,我得到了错误的数字。经过大量的尝试和错误,我发现是printf在输入结构成员时打印出了错误的数字。
以下代码给出了正确的结果:

int n_payload = cl_custom_iterator.get_payload();
std::cout << "get_payload: " << n_payload << "\n";

此代码给出错误的结果:

int n_payload = cl_custom_iterator.get_payload();
My_class::Node st_node = cl_custom_iterator.get_node();
printf("%p | get_payload: %d | get_node.n_payload: %d\n", cl_custom_iterator, n_payload, st_node.n_payload);

这是重现问题的最小示例:

#include <iostream>
#include <cstdio>
#include <vector>

class My_class
{
    public:
        //Troublemaker?
        struct Node
        {
            int n_payload;
        };
        //Constructor
        My_class(void)
        {
            Node st_node;
            for (int cnt = 0; cnt < 5; cnt++)
            {
                st_node.n_payload = 33+cnt;
                gast_my_array.push_back( st_node );
                std::cout << "Push " << cnt << " | Payload: " << gast_my_array[cnt].n_payload << "\n";
            }
        }

        template <typename T>
        class iterator
        {
            public:
                //! @brief constructor for the custom iterator
                iterator(std::vector<T>& ira_parent_vector, size_t in_starting_index = 0) :
                    gra_vector(ira_parent_vector),
                    gu32_index(in_starting_index)
                {
                    //Do nothing
                    return;
                }
                iterator<T>& operator++()
                {
                    gu32_index++;
                    return *this;
                }
                iterator<T> operator++(int)
                {
                    iterator<T> tmp(*this);
                    gu32_index++;
                    return tmp;
                }
                T &operator &(void)
                {
                    return &gra_vector[gu32_index];
                }
                int get_payload( void )
                {
                    return gra_vector[gu32_index].n_payload;
                }
                T get_node( void )
                {
                    return gra_vector[gu32_index];
                }
                bool operator==(const iterator<T>& icl_rhs_iterator) const
                {
                    return gu32_index == icl_rhs_iterator.gu32_index;
                }
                bool operator!=(const iterator<T>& icl_rhs_iterator) const
                {
                    return gu32_index != icl_rhs_iterator.gu32_index;
                }

            private:
                std::vector<T>& gra_vector;
                size_t gu32_index;
        };

        iterator<Node> begin()
        {
            return iterator<Node>(gast_my_array, 0);
        }
        iterator<Node> end()
        {
            return iterator<Node>(gast_my_array, gast_my_array.size());
        }
    private:
        std::vector<Node> gast_my_array;
};

int main(void)
{
    My_class my_class_instance;

    for (My_class::iterator<My_class::Node> cl_custom_iterator=my_class_instance.begin();cl_custom_iterator!=my_class_instance.end();cl_custom_iterator++)
    {
        int n_payload = cl_custom_iterator.get_payload();
        My_class::Node st_node = cl_custom_iterator.get_node();
        //std::cout << "get_payload: " << cl_custom_iterator.get_payload();
        std::cout << "get_payload: " << n_payload << "\n";
        printf("%p | get_payload: %d | get_node.n_payload: %d\n", cl_custom_iterator, n_payload, st_node.n_payload);
    }

    return 0;
}

这是我在我的机器上用mingw -std=c++11编译得到的输出
get_payload被馈送到std::cout并从节点手动提取结构成员给予正确的结果33、34......
get_payload输入到printf,打印出错误的数字1,2,...

Push 1 | Payload: 34
Push 2 | Payload: 35
Push 3 | Payload: 36
Push 4 | Payload: 37
get_payload: 33
006efec8 | get_payload: 0 | get_node.n_payload: 33
get_payload: 34
006efec8 | get_payload: 1 | get_node.n_payload: 34
get_payload: 35
006efec8 | get_payload: 2 | get_node.n_payload: 35
get_payload: 36
006efec8 | get_payload: 3 | get_node.n_payload: 36
get_payload: 37
006efec8 | get_payload: 4 | get_node.n_payload: 37

Process returned 0 (0x0)   execution time : 0.141 s
Press any key to continue.

我不知道我做错了什么。

固定代码

#include <iostream>
#include <vector>

class My_class
{
    public:
        struct Node
        {
            int n_payload;
        };
        //Constructor with example
        My_class()
        {
            Node st_node;
            for (int cnt = 0; cnt < 5; cnt++)
            {
                st_node.n_payload = 33+cnt;
                gast_my_array.push_back( st_node );
                std::cout << "Push " << cnt << " | Payload: " << gast_my_array[cnt].n_payload << "\n";
            }
        }
        //iterator
        template <typename T>
        class iterator
        {
            public:
                //! @brief constructor for the custom iterator
                iterator(std::vector<T>& ira_parent_vector, size_t in_starting_index = 0) :
                    gra_vector(ira_parent_vector),
                    gu32_index(in_starting_index)
                {
                    //Do nothing
                    return;
                }
                iterator<T>& operator++()
                {
                    gu32_index++;
                    return *this;
                }
                iterator<T> operator++(int)
                {
                    iterator<T> tmp(*this);
                    gu32_index++;
                    return tmp;
                }
                //FIX: I overload the * operator to get a reference to the element of std::vector of which I can easily get the address and content
                T &operator *()
                {
                    return gra_vector[gu32_index];
                }
                bool operator==(const iterator<T>& icl_rhs_iterator) const
                {
                    return gu32_index == icl_rhs_iterator.gu32_index;
                }
                bool operator!=(const iterator<T>& icl_rhs_iterator) const
                {
                    return gu32_index != icl_rhs_iterator.gu32_index;
                }

            private:
                std::vector<T>& gra_vector;
                size_t gu32_index;
        };
        iterator<Node> begin()
        {
            return iterator<Node>(gast_my_array, 0);
        }
        iterator<Node> end()
        {
            return iterator<Node>(gast_my_array, gast_my_array.size());
        }
    private:
        std::vector<Node> gast_my_array;
};

int main(void)
{
    My_class my_class_instance;

    for (My_class::iterator<My_class::Node> cl_custom_iterator=my_class_instance.begin();cl_custom_iterator!=my_class_instance.end();cl_custom_iterator++)
    {
        //FIX: printf has undefined behaviour with %p of an object. std::cout of the address of a reference will print out the address
        std::cout << "iterator address: " << &*cl_custom_iterator << " | payload: " << (*cl_custom_iterator).n_payload << "\n";
    }

    return 0;
}

输出(正确):

Push 0 | Payload: 33
Push 1 | Payload: 34
Push 2 | Payload: 35
Push 3 | Payload: 36
Push 4 | Payload: 37
iterator address: 0x711720 | payload: 33
iterator address: 0x711724 | payload: 34
iterator address: 0x711728 | payload: 35
iterator address: 0x71172c | payload: 36
iterator address: 0x711730 | payload: 37

Process returned 0 (0x0)   execution time : 0.109 s
Press any key to continue.
jogvjijk

jogvjijk1#

printf这样的C函数对迭代器这样的C++类型一无所知,这只会编译,因为printf是可变函数,因此没有对它的参数进行类型检查。
你可以试试这个

printf("%p | get_payload: %d | get_node.n_payload: %d\n", 
    &*cl_custom_iterator, n_payload, st_node.n_payload);

使用&*cl_custom_iterator应确保参数是指针,这是%p说明符所要求的。
虽然看了iterator类,但我不确定它是否会编译。

相关问题