Will creating a class template wrapper of a reference cause undefined behavoir?
Asked Answered
L

1

1

Here is a code snippet:

#include <iostream>
#include <string>
#include <vector>

template<class T>
class Wrapper {
public:
    T& t;
    explicit Wrapper2( T& obj ) : t(obj) {} 
};

class Car {
public:
    std::string color;
    std::string name;
    Car(){}
    Car( std::string colorIn, std::string nameIn ) : color( colorIn ), name( nameIn ){}
};

int _tmain( int iNumArguments, _TCHAR* pArgumentText[] ) {
    typedef Wrapper<Car> car;

    // Create 2 Containers
    std::vector<car> collection1;
    std::vector<car> collection2;

    // Populate collection 1 with reference objects
    collection1.push_back( Car("black", "Ford") );
    collection1.push_back( Car("white", "BMW") );
    collection1.push_back( Car("yellow", "Audi") );

    // use referenced object at index 0 in collection 1
    // to populate index 0 of collection 2
    collection2.push_back( collection1[0] );

    // Print Out index 0 of collection2's referenced object's fields
    std::cout << collection2[0].t.color << " " << collection2[0].t.name << std::endl;

    // Change collection2's index 0 referenced object's fields
    collection2[0].t.color = std::string( "green" );
    collection2[0].t.name  = std::string( "Gremlin" );

    // Print out collection1's index 0 referenced object's fields
    // and they are changed
    std::cout << collection1[0].ptr->color << " " << collection1[0].ptr->name << std::endl;
    return 0;
}

This does compile, build and run successfully in MSVS2015 CE without any errors.

Does this or can this generate Undefined Behavior and if so; How?

Larcher answered 5/1, 2017 at 11:12 Comment(8)
You probably want std::reference_wrapperConcha
@VittorioRomeo I know about std::reference_wrapper I just wanted to know if this would allow for undefined behavior.Larcher
You're bathing in UB because you're storing references to temporaries and using them later.Munition
@Munition Okay just wanted some verification. So in essence this can work as it did in this case, but depending on other circumstances, it is left up to the compiler to shred this apart and isn't reliable.Larcher
Thank you for the comments. So basically this would work as long as it remains in the same scope, but once you go out of that scope into a different stack frame; this would break down then.Larcher
The other compilers really dont like this code. That says a lot.Myelencephalon
@FrancisCugler there are no guarantees that it would work within the same scope, nor that it will stop working out of scope. But that's one possible outcome of undefined behaviour.Chartist
@PaulRooney That is funny and ironic because I don't have any other compiler only MSVS2015 CELarcher
C
2

Will creating a class template wrapper of a reference cause undefined behavoir?

No.

However misusing references (and pointers and iterators) in general does. If the referenced object is destroyed, that reference is left dangling. This happens to all references, not only those wrapped in a class - the wrapper has no effect. When the reference dangles, using it has undefined behaviour.

collection1.push_back( Car("black", "Ford") );

Here, The object is a temporary. The object exists until the end of push_back. After that the reference in the wrapper in the vector is dangling.

std::cout << collection2[0].t.color << " " << collection2[0].t.name << std::endl;

Here you use a dangling reference and the program has undefined behaviour.


Here is an example of using the wrapper that has no UB:

Car c;
collection1.push_back(c);
collection1[0].color = "black";
Chartist answered 5/1, 2017 at 11:28 Comment(3)
Thank you for the answer; this came about when answer a question on another post and they wanted to store objects into std::vector having multiple containers where if they modify say vector2[0] then vector1[0] would be modified as well similar to how some functionality of python works. Some suggested to them std::reference_wrapper and others shared_ptr. I was trying to show them a simple custom class template wrapper that would wrap either shared_ptr or reference.Larcher
@FrancisCugler your wrapper is a limited version of std::reference_wrapper. A reference wrapper works fine, if you have one "master" container that contains the objects themselves (not references) that is never modified, and other containers have references to the master. With the shared_ptr alternative, all containers are equal, and may be modified freely.Chartist
I asked a follow up question about this here: #41485542Larcher

© 2022 - 2024 — McMap. All rights reserved.