Cast of std::vector of same parameter type but with different constant qualifier

后端 未结 1 1808
傲寒
傲寒 2021-01-29 08:20

the question is pretty simple, is it in general safe a static cast (or some other cast) from

std::vector< Foo >

to

std::         


        
1条回答
  •  感情败类
    2021-01-29 08:43

    Ignoring that you said std::vector for the moment and pretending you had some other less well defined vector implementation. Your code would be technically unsafe not because T and T const are quite different but because the C++ language permits vector and vector to be specialised in ways that are quite different. Consider the following code:

    #include 
    
    template 
    struct vector {
        T* start_;
        T* end_;
        T* cap_end_;
    };
    
    template 
    struct vector {
        bool gotcha_;
        T* start_;
        T* end_;
        T* cap_end_;
    };
    
    struct foo { };
    
    int
    main()
    {
        std::cout
            << sizeof(vector) << '\n'
            << sizeof(vector) << '\n'
            ;
    }
    

    Note that there are other more pernicious changes that could make your life miserable. Such as the following where the members are reordered:

    #include 
    
    template 
    struct vector {
        T* start_;
        T* end_;
        T* cap_end_;
    };
    
    template 
    struct vector {
        T* end_;
        T* cap_end_;
        T* start_;
    };
    
    template 
    long size(vector const& v)
    {
        return v.end_ - v.start_;
    }
    
    struct foo { };
    
    int
    main()
    {
        vector v;
        v.start_ = new foo[10];
        v.end_ = v.start_ + 1;
        v.cap_end_ = v.start_ + 10;
    
    
        std::cout
            << size(v) << '\n'
            << size(*reinterpret_cast*>(&v)) << '\n'
            ;
    
        return 0;
    }
    

    Wrt to std::vector, I am not familiar enough with the fine details of the standard library specification to know whether such specialisations would be conformant or not. Perhaps someone more well versed in the standard can comment.

    Note some of what I said in answer to Casting templated class to more general specialization may help explain this problem.

    To address your question about detecting specialisations there are ways to make your code unsafe by using no specialisations of the class but overloaded non-member functions and I am o not sure how you would detect that. Such as in the following:

    #include 
    
    template 
    struct vector {
        T* start_;
        T* end_;
        T* cap_end_;
    };
    
    
    template 
    void init(vector& v, size_t sz, size_t cap)
    {
        v.start_ = new T[cap];
        v.end_ = v.start_ + sz;
        v.cap_end_ = v.start_ + cap;
    }
    
    template 
    void init(vector& v, size_t sz, size_t cap)
    {
        v.end_ = new T const[cap];
        v.cap_end_ = v.end_ + sz;
        v.start_ = v.end_ + cap;
    }
    
    template 
    long size(vector& v)
    {
        return v.end_ - v.start_;
    }
    
    template 
    long size(vector& v)
    {
        return v.cap_end_ - v.end_;
    }
    
    struct foo { };
    
    int
    main()
    {
        vector v;
        init(v, 1, 10);
    
        std::cout
            << size(v) << '\n'
            << size(*reinterpret_cast*>(&v)) << '\n'
            ;
    }
    

    Enough with the bad news. The good news is that if you want to take an existing object with a general interface and restrict or adjust what can be done with that object there is are some simple, safe and comprehensible ways of doing that. Take a look at std::stack http://www.sgi.com/tech/stl/stack.html or alternatively this answer https://stackoverflow.com/a/994925/453436 to What is Proxy Class in C++

    0 讨论(0)
提交回复
热议问题