-1

I am trying to use the following id function in C++. I would have assumed that I can simply do;

typedef int v3[3];

v3 & id( v3 & in )
{
  in[0] = in[1] = in[2] = 1;
  return in;
}

int main()
{
  v3 & v = id( v );
  return 0;
}

However this leads to a segfault with g++ (this is not clear to me). Since I can do the following with scalar-type:

int & zero( int & in )
{
  in = 0;
  return in;
}

int main()
{
  int i = zero( i );
  return 0;
}

How can I use id with a single line of code ? I'd like to avoid an ugly solution such as:

int main()
{
  v3 v;
  v3 & w = id( v );
}

Of course I do not want to use std::vector or std::array (c++11). So I am really interested why my naive solution is actually undefined behavior.

EDIT: std::vector will require dynamic allocation which in my case should be avoid (I need to manipulation thousands of vr3). I cannot use std::array since I am required to stick to c++03. Obviously one could not guess my requirements.

malat
  • 12,152
  • 13
  • 89
  • 158
  • You allocate storage for a reference named `v`. What does it point to and where do you write when you do `v[0] = v[1] = v[2] = 1;`!? – StoryTeller - Unslander Monica Dec 22 '15 at 11:48
  • If you're interested in the "Is this undefined behavior?" and "Why does the compiler compile it?" aspects, see here: http://stackoverflow.com/questions/25717740/why-is-gcc-tricked-into-allowing-undefined-behavior-simply-by-putting-it-in-a-lo – John Zwinck Dec 22 '15 at 11:49
  • I am really interested, what could be a good reason to not use `std::vector<>` or `std::array<>`. It must be so obvious to you, that you tell us, that "of course" you don't want to use them. Please be a bit more elaborate on this issue. – cdonat Dec 22 '15 at 12:06

6 Answers6

5

This:

v3 & v = id( v );

And this:

int i = zero( i );

Are nonsense, because you cannot use something in its own initializer. Some compilers will warn you about this, but some won't.

You could make a macro:

#define V3_UNIT {1,1,1}

Now you can do:

v3 v = V3_UNIT;

PTHREAD_MUTEX_INITIALIZER is one common example of this technique in the wild.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
4

Use std::array:

#include <array>

using v3 = std::array<int, 3>;

v3 id()
{
  return {{ 1, 1, 1 }};
}

int main()
{
  v3 v = id();
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • As said in my post, I cannot use `std::array` (or a solution based on struct return). I need to return an array. – malat Dec 22 '15 at 11:45
  • @malat, but you aren't returning an array, you are returning a reference to an array. – StoryTeller - Unslander Monica Dec 22 '15 at 11:47
  • @malat It's either `std::array` or `std::vector` (which should be the preferred solution before C++11), or your "ugly" solution. That's the choices you have (unless you want to allocate memory dynamically, which I really don't recommend). – Some programmer dude Dec 22 '15 at 11:51
  • @malat you can use `std::array<>` and call `std::array<>::data()`, whenever you have to pass on a C array to legacy code. – cdonat Dec 22 '15 at 12:00
4

I am really interested why my naive solution is actually undefined behavior.

It's UB because: You initialize the reference v with the return value of id, and id returns the reference that is it's parameter. The parameter passed to id is v, so therefore you initialize v with it's uninitialized self, without ever allocating an object to refer to.

How can I use id with a single line of code ?

Well, you could simply type two statements on one line (and get rid of the redundant assignment):

v3 v; id(v);

But, it would be simpler to:

v3 v{1, 1, 1};

I need to return an array.

If you read this page carefully, you'll find out that you're out of luck. Arrays can not be returned or passed as parameters. What you can do is use a wrapper class that holds the array inside. But there is no need to implement it yourself because the standard library already provides one: std::array.

Of course I do not want to use std::vector or std::array

You've painted yourself into a corner with your conflicting wants. You'll need to reimplement std::array yourself then. I don't recommend you do that.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

Your problem is that in your sample main in the v case you don't have a v3 anywhere. You only have references to v3s, and there is nothing for them to refer to.

You get away with it in the int case because you have a real genuine int to refer to. (But it may well be undefined behaviour - it is certainly very dodgy.)

1

This code is undefined behaviour:

v3 & v = id( v );

under clang you will get warning:

warning: reference 'v' is not yet bound to a value when used within its own initialization [-Wuninitialized]


[edit]

Actually I am not 100% sure if self assignment of reference is UB or ill-formed code, I have found interesting discussions on this topic:

Why is GCC tricked into allowing undefined behavior simply by putting it in a loop? http://www.open-std.org/pipermail/ub/2014-September/000506.html

which suggests that it should be rather ill-formed - but it looks like the discussion is in progress. Most common comment on such code is nonsense but I suppose only due to the fact that its hard to find appropiate part of standard on this.

Community
  • 1
  • 1
marcinj
  • 48,511
  • 9
  • 79
  • 100
0

You may initial values in braces {}. Like: in = {1,1,1};