"There shall be no arrays of references"

closed account (10oTURfi)
Then why does this work?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>
using namespace std;

template <class T>
struct node
{
    node(T& data) : data(data) {}
    const T& data;
};

int main()
{
    vector<node<int> > nodes;
    int a = 1, b = 2;
    nodes.push_back(node<int>(a));
    for(int i=0; i<49; ++i)
        nodes.push_back(node<int>(b));
    a = 3; b = 4;
    cout << "nodes.begin()->data: " << nodes.begin()->data << endl;
    cout << "nodes.size(): " << nodes.size() << endl;
    cout << "sizeof(nodes): " << sizeof(nodes) << endl;
}


Output:
nodes.begin()->data: 3
nodes.size(): 50
sizeof(nodes): 16


NOTE: No matter how many elements in vector are there, sizeof() will be 16.
Last edited on
What are you compiling that with? It doesn't work.


157.cpp:6:8: error: cannot define the implicit default assignment operator for 'struct node<int>', because non-static reference member 'data' can't use default assignment operator

Last edited on
closed account (10oTURfi)
With MSVC++ 2010.

Just compiled in release mode and now sizeof(nodes) is 16

1>------ Build started: Project: Array of references, Configuration: Release Win32 ------
1>  main.cpp
1>  Generating code
1>  Finished generating code
1>  Array of references.vcxproj -> F:\Array of references\Release\Array of references.exe
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Last edited on
g++ and clang++ both throw up on it with the error above.
Compilied on VC 2008 and got:

Error 2 error C2582: 'operator =' function is unavailable in 'node<T>' c:\program files (x86)\microsoft visual studio 9.0\vc\include\xutility 3133
closed account (10oTURfi)
Wow. Thats interesting.
Anyone with VC++ 2010?

I think I have just found a very usefull bug *happy*
for variety, a few more compilers:

HP
"test.cpp", line 6: error #2397: implicitly generated assignment operator cannot copy:
            reference member "node<T>::data [with T=int]"


IBM
"test.cpp", line 9.14: 1540-0718 (S) An implicit copy assignment operator cannot be created for class with a member of type "const int &".
"test.cpp", line 6.8: 1540-0719 (I) The previous message was produced while processing the implicit member function "node<int>::operator=(const node<int> &)".


Sun
Error: node<int> has a reference member data and cannot be assigned.
Where: While instantiating "std::vector<node<int> >::__insert_aux(node<int>*, const node<int>&)".



I think I have just found a very usefull bug *happy*

Useful for what purpose?
These errors are all about the implicit compiler generated copy assignment a.k.a assignment operator
(=) - This is an issue because the assignment operator uses
existing objects ( existing object = existing object) and so will
bail if the class contains const or & variables.

The compiler can create a copy constructor as this is just an
memory overlay (and the object on the left hand side is a new as yet
unitialised object.

The copy constructor is all that isreally need in the above code
(although some compiler implementation details may cause the code to fail)

Summary:
the MSVC 10 thing is not really a bug.

closed account (10oTURfi)
@Cubbi
Array of pointers costs memory, while array of references shouldn't even exist (that vector is supposed to be "empty")

If I had array of pointers in this example, it would have used 200 bytes of memory, while sizeof(nodes) reports only 16!

Isnt that usefull enough?

This could be hacked even more to allow me to change the what reference refers to. I think I'll write that tomorow.
Last edited on
False. When you have references as members of a class, they are commonly implemented as pointers (though it depends on the implementation):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

class a
{
    char *p;
};
class b
{
    char &r;
    b(); //these are just so the example compiles
    b(const b &);
    b &operator=(const b &);
};

int main()
{
    std::cout << sizeof(a) << std::endl;
    std::cout << sizeof(b) << std::endl;
}
4
4
Proof: http://ideone.com/my630
closed account (10oTURfi)
@LB
Ok so that is contrary to output my program generated when compiled using msvc++. If we assume that references are implemented as pointers, there would only be 4 objects in that vector, but there are 50


Now I am even more confused...


I should really stop writing these proof of concept programs...
A structure can't magically change its size during runtime, it's always a compile-time constant.
vectors dynamically allocate memory for their elements and keep a pointer to it.
nodes.capacity()*sizeof(node) tells you how much memory it actually allocated.
Last edited on
guestgulkan wrote:
The copy constructor is all that isreally need in the above code

No; it would violate the shall clause in the C++ standard ("For vector and deque, T shall also be CopyAssignable")
"For vector and deque, T shall also be CopyAssignable"


This occurs in the context of specific expressions/operations involving sequence containers. None of those are used here. If you include an operation that does have this requirement, the compilation fails. (Even without an operation with that requirement invoked, VC++ generates a warning that operator= could not be generated.)
closed account (10oTURfi)
Marking as solved.
Thanks everyone, especially LB and Athar.
Did some more testing and it looks like those indeed are implemented as pointers, and sizeof(node) is 4.
cire wrote:
If you include an operation that does have this requirement, the compilation fails

On further reading, you're right vector::push_back only requires CopyInsertable. It's vector::insert that requires CopyAssignable that I quoted earlier.
HI , I am not able to compile the code as


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
#include "stdafx.h"
#include <iostream>
#include <string> 
#include <vector>
using namespace std;  

template <class T>
struct node
{
	node(T& data1) :data(data1){ }
	node ( const node& n ) { data = n.data ; }
     T& data;
};




int _tmain(int argc, _TCHAR* argv[])
{
	vector<node<int> > nodes;
   int a = 1, b = 2;
   nodes.push_back(node<int> (a));
   for(int i=0; i<49; ++i)
        nodes.push_back(node<int>(b));
    a = 3; b = 4;
    cout << "nodes.begin()->data: " << nodes.begin()->data << endl;
    cout << "nodes.size(): " << nodes.size() << endl;
    cout << "sizeof(nodes): " << sizeof(nodes) << endl;
	std::cout << sizeof(a) << std::endl;
    std::cout << sizeof(b) << std::endl;
	return 0;
}


The output is ..
1>------ Build started: Project: ConstNode060420122357, Configuration: Debug Win32 ------
1>Compiling...
1>ConstNode060420122357.cpp
1>j:\work\constnode060420122357\constnode060420122357\constnode060420122357.cpp(14) : error C2758: 'node<T>::data' : must be initialized in constructor base/member initializer list
1>        with
1>        [
1>            T=int
1>        ]
1>        j:\work\constnode060420122357\constnode060420122357\constnode060420122357.cpp(15) : see declaration of 'node<T>::data'
1>        with
1>        [
1>            T=int
1>        ]
1>        j:\work\constnode060420122357\constnode060420122357\constnode060420122357.cpp(14) : while compiling class template member function 'node<T>::node(const node<T> &)'
1>        with
1>        [
1>            T=int
1>        ]
1>        j:\work\constnode060420122357\constnode060420122357\constnode060420122357.cpp(25) : see reference to class template instantiation 'node<T>' being compiled
1>        with
1>        [
1>            T=int
1>        ]
1>Build log was saved at "file://j:\Work\ConstNode060420122357\ConstNode060420122357\Debug\BuildLog.htm"
1>ConstNode060420122357 - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

How do i remove these error ?
Last edited on
Topic archived. No new replies allowed.