How to change pointer from vector element to vector.

Pages: 12
I've written a function which gets back a reference to a location in a vector. I want the pointer to point to this entire vector not just the location of the element. how would i do that?
I've written a function which gets back a reference to a location in a vector. I want the pointer to point to this entire vector not just the location of the element. how would i do that?


You cannot.

Is it a reference or a pointer?
-- If it's a reference: you cannot change references since references have no value.
-- If it's a pointer, given some std::vector<T>, it's not possible to take a T* and assign it a std::vector<T>*; the types differ. (Yes, I know this isn't exactly what you said, but it's what I think you mean.)

Your only hope is that the referent has a link to its' owner's container. That would almost certainly be a design mistake.

This seems like an XY problem.
http://xyproblem.info/

What's your actual goal?

Edit:
Yeah, if you actually have the vector(s) laying around, you can just take &v. If you do, use @JLBorges' solution
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <vector>

template < typename T > bool is_element_of( T* ptr_item, std::vector<T>* vec )
{
    return ptr_item && vec && !vec->empty() &&
           ptr_item >= std::addressof( vec->front() ) &&
           ptr_item <= std::addressof( vec->back() ) ;
}

template < typename T >
std::vector<T>* addressof_containing_vector( T* ptr_item, std::vector< std::vector<T>* > vectors )
{
    for( auto ptr_vec : vectors ) if( is_element_of( ptr_item, ptr_vec ) ) return ptr_vec ;
    return nullptr ;
}

http://coliru.stacked-crooked.com/a/b16c8649f5624c1c
@JLBorges
There was a proposal for a ContiguousIterator:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf
It would fit nicely above, but I suppose it was dropped (I can't find information to the contrary).
Last edited on
> If you do, use @JLBorges' solution

Caveat: pedantically, the code relies on unspecified behaviour.
ContiguousIterator exists as a concept in C++17. http://en.cppreference.com/w/cpp/iterator
However, there is no std::contiguous_iterator_tag

N4284:
There are four containers in the standard library that guarantee contiguous storage: vector, string, valarray, and array. In the Library Fundamentals TS, there is also string_view. This paper introduces the term "contiguous iterator" as a refinement of random-access iterator, without introducing a corresponding contiguous_iterator_tag, which was found to break code during the Issaquah discussions of Nevin Liber's paper N3884 "Contiguous Iterators: A Refinement of Random Access Iterators".
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html
The code relies on unspecified behaviour.

Where? I can't find it.
5.9/3 and 5.9/4 (N4640 February 2017) Relational operators

3. Comparing unequal pointers to objects is defined as follows:
— (3.1) If two pointers point to different elements of the same array, or to subobjects thereof, the pointer to the element with the higher subscript compares greater.
— (3.2) If two pointers point to different non-static data members of the same object, or to subobjects of such members, recursively, the pointer to the later declared member compares greater provided the two members have the same access control and provided their class is not a union.
— (3.3) Otherwise, neither pointer compares greater than the other.

4. If two operands p and q compare equal, p<=q and p>=q both yield true and p<q and p>q both yield false . Otherwise, if a pointer p compares greater than a pointer q , p>=q , p>q , q<=p , and q<p all yield true and p<=q, p<q, q>=p, and q>p all yield false. Otherwise, the result of each of the operators is unspecified.


Note: In C++11, the equivalent of 3.3 here was " Other pointer comparisons are unspecified."
You could use this to avoid the undefined unspecified behavior:
1
2
3
4
5
6
7
8
9
template < typename T >
bool is_element_of( T* ptr_item, std::vector<T>* vec )
{
    if (!ptr_item || vec->empty())
        return false;
    auto begin = &(*vec)[0];
    auto end = begin + vec->size() - 1;
    return ptr_item >= begin && ptr_item <= end;
}
Last edited on
There was no undefined behaviour.

The code posted, if it compiles without errors (there is no guarantee that it will),
1
2
3
    auto begin = &(*vec)[0];
    auto end = begin + vec->size() - 1;
    return ptr_item >= begin && ptr_item <= end;
would still have unspecified behviour.
if it compiles without errors (there is no guarantee that it will)
What do you mean?

Why is the behavior of that snippet unspecified? begin points to an array and end points to an offset in that array.
> if it compiles without errors (there is no guarantee that it will)
>> What do you mean?

I'm sorry, I misread it. It will compile without errors.

EDIT: It will compile without errors, provided the type T either has not declared an overloaded unary & operator, or if it is declared, it is public and returns an object that can be compared with a pointer to T.


> begin points to an array and end points to an offset in that array.

begin points to the first element of an array, and end points to the last element of the same array.


> Why is the behavior of that snippet unspecified?

For precisely the same reason that the earlier snippet has unspecified behaviour.
ptr_item may not point to an element in the same array or to point to a notional one-past-the last element of that array.
Repeat: http://www.cplusplus.com/forum/beginner/211681/#msg990989
Last edited on
ptr_item may not point to an element in the same array
Darn. You're right.

Sorry, but I don't see any difference between the statements "X points to an array" and "X points to the first element of an array".
The statements "X points to an array" and "X points to the first element of an array" mean quite different things (assuming that the array being talked about is the same array).
Sadly, there are many programmers who are unable perceive the clear distinction between the two.

Studying this snippet may help:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <type_traits>

int main()
{
    const std::size_t N = 123456 ;
    static int a[2][N] {} ;

    auto ptr_int = a[0] ; // pointer to int (pointer to first element of a[0])
    auto ptr_array = std::addressof( a[0] ) ; // pointer to array of N int

    using type_one = decltype(ptr_int) ;
    using type_two = decltype(ptr_array) ;

    std::cout << "are they the same? " << std::boolalpha
              << ( std::is_same<type_one,type_two>::value ? "yes\n" : "no\n" ) // no

              << "is there an implicit conversion from one to another? "
              << ( std::is_convertible<type_one,type_two>::value ? "yes " : "no " ) // no
              << ( std::is_convertible<type_two,type_one>::value ? "yes\n" : "no\n" ) ; // no

    std::cout << "                ptr_int+1 " << ptr_int+1 << '\n'
              << "std::addressof( a[0][1] ) " << std::addressof( a[0][1] ) << '\n'
              << "              ptr_array+1 " << ptr_array+1 << '\n'
              << "   std::addressof( a[1] ) " << std::addressof( a[1] ) << '\n' ;


    // ptr_int = ptr_array ; // *** error: no conversion
    ptr_int = *ptr_array ; // fine: array to pointer decay

    // ptr_array = ptr_int ; // *** error: no conversion
    // bool eq = ptr_int == ptr_array ; // *** error: no equality comparison

    int& r = *ptr_int ; // fine
    // int& r2 = *ptr_array ; // error: invalid reference initialisation
    int(&ra)[N] = *ptr_array ; // fine
    // int(&ra2)[N] = *ptr_int ; // error: invalid reference initialisation

    ptr_array = new int[5][N] {} ; // fine
    // ptr_int = new int[5][N] {} ; // *** error: no conversion

    delete[] ptr_array ;
}

http://coliru.stacked-crooked.com/a/07270b947ddbaf45
I'll post my code to show you what I mean but looking at what i wrote it does in fact feel like a design flaw. To clarify I have a vector<CardTemplate>& playerOne There is one for each of the three players. I also have a pointer to a vector but i was thinking of changing it to a reference to the card location but then its not the vector containing it. (where my question came from) Basically I'm determining who has the lowest card so that player can choose which cards they want to play.

The function I'm posting is pointing to the vector but i dont think ill be able to point to the players in order from lowest card to highest card.

Structure to pass multiple variable in function if needed:
1
2
3
4
5
6
7
8
9
10
struct lowCardStruct
{
    //change int to pointer and add 4 pointers
    std::vector<CardTemplate>* playerA;
    std::vector<CardTemplate>* playerB;
    std::vector<CardTemplate>* playerC;
    std::vector<CardTemplate>* playerD;
    int playerWithLowCard;
    CardTemplate lowestCard;
};


Class:
1
2
3
4
5
6
7
8
9
10
11
12
class CardTemplate
{
public:
    //Add another int for cardStrength and number all card based on str 0-51. 0 = 3 diamond and 51 = 2 spade
    std::string suit;
    int suitStrength;
    int cardNum;
    //int cardStrength;
    
    //potentially add string for 11+ cardNum instead of ints

};


Function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
lowCardStruct determineLowestCard(CardTemplate pOneLowest, CardTemplate pTwoLowest, CardTemplate pThreeLowest, std::vector<CardTemplate>& playerOne, std::vector<CardTemplate>& playerTwo, std::vector<CardTemplate>& playerThree)
{
    //Place all cards into a vector
    std::vector<CardTemplate> lowestCardsPlaying;
    lowestCardsPlaying.push_back(pOneLowest);
    lowestCardsPlaying.push_back(pTwoLowest);
    lowestCardsPlaying.push_back(pThreeLowest);
    
    //Create structure for lowest card in play
    lowCardStruct lowCardInPlay;
    
    //int for which player was the lowest card made large to find error
    int playerWithLowCard = 666;
    
    //Make lowest card first in vector then compare
    CardTemplate lowestCardPlaying = lowestCardsPlaying[0];
    
    //cycle through all of the player's lowest cards
    for(int i = 0; i < lowestCardsPlaying.size(); i++)
    {
        if(lowestCardsPlaying[i] < lowestCardPlaying)
        {
            lowestCardPlaying = lowestCardsPlaying[i];
            playerWithLowCard = i;
        }
    }
    //Set lowCardInPlay variables
    lowCardInPlay.lowestCard = lowestCardPlaying;
    lowCardInPlay.playerWithLowCard = playerWithLowCard;
    //Set playerA starting player
    if(playerWithLowCard == 0)
    {
        lowCardInPlay.playerA = &playerOne;
    }
    else if (playerWithLowCard == 1)
    {
        lowCardInPlay.playerA = &playerTwo;
    }
    else if (playerWithLowCard == 2)
    {
        lowCardInPlay.playerA = &playerThree;
    }
    //Remove playerA and compare player three and four cards for playerB second and playerC third.
    lowestCardsPlaying.erase(lowestCardsPlaying.begin() + playerWithLowCard);
    //compare remaining two elements to determine who playerB and playerC will be
    if(lowestCardsPlaying[0] < lowestCardsPlaying[1])
    {
        
    }
    return lowCardInPlay;
}


The statements "X points to an array" and "X points to the first element of an array"


Does this mean if X points to the array its pointing at the entire container? Vs just a single element at a time?
Last edited on
Okay, but vectors are one-dimensional. Can you do the same with a one-dimensional array?
> Can you do the same with a one-dimensional array?

In the snippet above, a[0] is a one-dimensional array.

If that is hard to understand:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <type_traits>

int main()
{
    const std::size_t N = 123456 ;
    static int a[N] {} ;

    auto ptr_int = a ; // pointer to int (pointer to first element of a)
    auto ptr_array = std::addressof(a) ; // pointer to array of N int (pointer to a)

    using type_one = decltype(ptr_int) ;
    using type_two = decltype(ptr_array) ;

    std::cout << "are they the same? " << std::boolalpha
              << ( std::is_same<type_one,type_two>::value ? "yes\n" : "no\n" ) // no

              << "is there an implicit conversion from one to another? "
              << ( std::is_convertible<type_one,type_two>::value ? "yes " : "no " ) // no
              << ( std::is_convertible<type_two,type_one>::value ? "yes\n" : "no\n" ) ; // no

    std::cout << "                ptr_int+1 " << ptr_int+1 << '\n'
              // << "std::addressof( a[0][1] ) " << std::addressof( a[0][1] ) << '\n'
              << "              ptr_array+1 " << ptr_array+1 << '\n' ;
              // << "   std::addressof( a[1] ) " << std::addressof( a[1] ) << '\n' ;


    // ptr_int = ptr_array ; // *** error: no conversion
    ptr_int = *ptr_array ; // fine: array to pointer decay

    // ptr_array = ptr_int ; // *** error: no conversion
    // bool eq = ptr_int == ptr_array ; // *** error: no equality comparison

    int& r = *ptr_int ; // fine
    // int& r2 = *ptr_array ; // error: invalid reference initialisation
    int(&ra)[N] = *ptr_array ; // fine
    // int(&ra2)[N] = *ptr_int ; // error: invalid reference initialisation

    ptr_array = new int[5][N] {} ; // fine
    // ptr_int = new int[5][N] {} ; // *** error: no conversion

    delete[] ptr_array ;
}

http://coliru.stacked-crooked.com/a/6aee320d8cb5170f
> The statements "X points to an array" and "X points to the first element of an array"
>> Does this mean if X points to the array its pointing at the entire container? Vs just a single element at a time?

Yes.


May be something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>

struct card
{
    int suitStrength;
    int cardNum;
    // ...
};

bool operator< ( const card& a, const card& b )
{ return std::tie(a.suitStrength,a.cardNum) < std::tie(b.suitStrength,b.cardNum) ; }

// return the lowest card in the hand
const card& lowest_card( std::vector<card>* hand )
{
    if( !hand || hand->empty() ) throw std::invalid_argument( "bad arg hand" ) ;
    return *std::min_element( hand->begin(), hand->end() ) ;
}

struct low_card_struct
{
    // first == low card of the hand second == pointer to hand
    using low_card_pair = std::pair< card, std::vector<card>* > ;

    std::vector<low_card_pair> low_card_and_hand ;
};

// return low_card_struct with the member low_card_and_hand ordered on the low cards in each hand
low_card_struct order_on_lowest_card( std::vector< std::vector<card>* > hands )
{
    low_card_struct lcs ;
    for( auto ptr : hands ) lcs.low_card_and_hand.emplace_back( lowest_card(ptr), ptr ) ;

    // sort on the lowest card in each hand
    // note: the the comparison of pairs is lexicographic
    //       ie. the member first (the lowest card in the hand) is more significant
    //           in determining the order, which is what we want
    std::sort( std::begin(lcs.low_card_and_hand), std::end(lcs.low_card_and_hand) ) ;
    return lcs ;
}

int main()
{
    std::vector<card> one(13), two(13), three(13), four(13) ;
    // ... place cards into hands one, two, three, four

    using std::addressof ;
    low_card_struct lcs = order_on_lowest_card( { addressof(one), addressof(two), addressof(three), addressof(four) } ) ;

    // lcs.low_card_and_hand[0].first: lowest card in the four hands,
    // lcs.low_card_and_hand[0].second pointer to hand holding that lowest card

    // lcs.low_card_and_hand[1].first: lowest card in the remaining three hands,
    // lcs.low_card_and_hand[1].second pointer to hand holding that lowest card

    // etc.
}
i'd like to raise a general query about the basis of this post, if I may:
a function which gets back a reference to a location in a vector. I want the pointer to point to this entire vector not just the location of the element.
would it be considered good design, for the calling function (here main()) to require access to the entire container when it receives info about just one element of the container or, if such holding container access is indeed required by the caller, shouldn't the called function be implemented in such that it provides that access to the caller(s)?
would it be considered good design ...

In my opinion, probably not.

Hunt and Thomas suggest the aphorism "tell, don't ask"; the suggestion is violated by OP's code.

The first step of OP's process is to query to see what container the object is contained in.
Normally queries are a bad idea. This is because if you are making a decision for an object based on the state of some external object, that logic probably should belong to the external object.

I think the remedy is described by Stroustrup at the beginning of TC++PL where he says
"represent ideas directly in code". Here, OP is using a vector to represent a hand of cards, but a vector is simply a data structure; it's interface is to a vector, not to a hand. Naturally the data structure holding the cards is an implementation detail.

I would probably approach the problem by defining some abstraction for a hand and use the hand itself to find the lowest-valued card(s) as required.
Last edited on
Pages: 12