473,403 Members | 2,222 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,403 software developers and data experts.

Passing reference to variable out of scope

Hello Group,

please consider the following code

#include <vector>
#include <iostream>

#define USE_CONST
#define USE_STRING

class a {
public:
#ifdef USE_CONST
const std::string &moo;
a(const std::string &moo) : moo(moo) { };
#else
std::string &moo;
a(std::string &moo) : moo(moo) { };
#endif

void show() {
std::cerr << "String: '" << moo << "'" << std::endl;
};
};

int main() {
#ifdef USE_STRING
std::string str = std::string("Das ist ein Test!");
a abc = a(str);
abc.show();
#else
a xyz = a(std::string("Das ist ein Test!"));
xyz.show();
#endif

return 0;
}

There are four possible combinations of USE_CONST and USE_STRING:

1 USE_STRING && !USE_CONST =Fine
2 USE_STRING && USE_CONST =Fine
3 !USE_STRING && !USE_CONST =Compile Error
4 !USE_STRING && USE_CONST =Compiles, but behaves weird

So it is clear to me that when using number 3, the compiler throws an
error - since the created string object goes out of scope (and lifespan)
immediately after the constructor of "a" is called.

But what bewilders me a bit is that example #4 compiles cleanly without
any warning - yet there is no string output (it's just empty); probably
because it has already been destroyed when the implicit std::string's
destructor was called.

This seems intriguing. The string is already destroyed, however a may
keep a reference (moo) to it? How is that possible?

Greetings,
Johannes

--
"PS: Ein Realname wäre nett. Ich selbst nutze nur keinen, weil mich die
meisten hier bereits mit Namen kennen." -- Markus Gronotte aka "Makus"
aka "Kosst Amojan" aka "maqqusz" in de.sci.electronics
<45**********************@newsspool3.arcor-online.net>
Nov 19 '07 #1
7 5750
Johannes Bauer wrote:
So it is clear to me that when using number 3, the compiler throws an
error - since the created string object goes out of scope (and
lifespan) immediately after the constructor of "a" is called.
No, the compiler throws an error because you are trying to bind a const
reference to a non-const reference. This is completely unrelated to the
lifetime issue.
>
But what bewilders me a bit is that example #4 compiles cleanly
without any warning - yet there is no string output (it's just empty);
probably because it has already been destroyed when the implicit
std::string's destructor was called.
Jep. In your case, the lifetime of the string expression extends up to
the lifetime of the complete expression (the construction of xyz), but
not further.
>
This seems intriguing. The string is already destroyed, however a may
keep a reference (moo) to it? How is that possible?
References do not protect the referenced object from destruction - if an
objects dies before the reference to it vanishes, you end up with a
"dangling reference". In that respect, a reference isn't much better
that a pointer.

Btw. as a certain optimization and a feature to dumbfound beginners and
intermediate users, the following code:

const string &x="Hallo";
cout << x;

is correct.

--
IYesNo yes=YesNoFactory.getFactoryInstance().YES;
yes.getDescription().equals(array[0].toUpperCase());
Nov 19 '07 #2
Marco Manfredini schrieb:
Johannes Bauer wrote:
>So it is clear to me that when using number 3, the compiler throws an
error - since the created string object goes out of scope (and
lifespan) immediately after the constructor of "a" is called.

No, the compiler throws an error because you are trying to bind a const
reference to a non-const reference. This is completely unrelated to the
lifetime issue.
Oh, okay. Coming from C, I'm not used to a compiler being so strict on
the "const" keyword, but I like it.
>This seems intriguing. The string is already destroyed, however a may
keep a reference (moo) to it? How is that possible?

References do not protect the referenced object from destruction - if an
objects dies before the reference to it vanishes, you end up with a
"dangling reference". In that respect, a reference isn't much better
that a pointer.
Okay, that sounds a little bit dangerous - as I thought C++ should
guarantee references are always valid (or at least always not-NULL).
Would at least valgrind detect access to a dangling reference?
Btw. as a certain optimization and a feature to dumbfound beginners and
intermediate users, the following code:

const string &x="Hallo";
cout << x;
Although I don't consider myself to be a greenhorn, this still
dumbfounds me. The assignment operator is overloaded for const char* to
invoke the constructor of std::string, meaning

const string &x = std::string("Hallo");

So - tell me, why doesn't the lifespan of the *actual* string end in
that same line, leaving x to be a dangling reference?

Greetings,
Johannes

--
"PS: Ein Realname wäre nett. Ich selbst nutze nur keinen, weil mich die
meisten hier bereits mit Namen kennen." -- Markus Gronotte aka "Makus"
aka "Kosst Amojan" aka "maqqusz" in de.sci.electronics
<45**********************@newsspool3.arcor-online.net>
Nov 19 '07 #3
Johannes Bauer wrote:
const string &x = std::string("Hallo");

So - tell me, why doesn't the lifespan of the *actual* string end in
that same line, leaving x to be a dangling reference?
There is an explicit rule, that if a temporary is used to initialize a
const reference with *scoped* lifetime (ie. auto & global), then the
temporary remains active for the lifetime of the reference. That is the
compiler treats this (more or less) as:

const string __tmpval = std::string("Hallo");
const string &x = __tmpval;
--
IYesNo yes=YesNoFactory.getFactoryInstance().YES;
yes.getDescription().equals(array[0].toUpperCase());
Nov 19 '07 #4
On Nov 19, 4:13 pm, Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Marco Manfredini schrieb:
Johannes Bauer wrote:
So it is clear to me that when using number 3, the compiler throws an
error - since the created string object goes out of scope (and
lifespan) immediately after the constructor of "a" is called.
No, the compiler throws an error because you are trying to bind a const
reference to a non-const reference. This is completely unrelated to the
lifetime issue.

Oh, okay. Coming from C, I'm not used to a compiler being so strict on
the "const" keyword, but I like it.
This seems intriguing. The string is already destroyed, however a may
keep a reference (moo) to it? How is that possible?
References do not protect the referenced object from destruction - if an
objects dies before the reference to it vanishes, you end up with a
"dangling reference". In that respect, a reference isn't much better
that a pointer.

Okay, that sounds a little bit dangerous - as I thought C++ should
guarantee references are always valid (or at least always not-NULL).
Would at least valgrind detect access to a dangling reference?
Btw. as a certain optimization and a feature to dumbfound beginners and
intermediate users, the following code:
const string &x="Hallo";
cout << x;

Although I don't consider myself to be a greenhorn, this still
dumbfounds me. The assignment operator is overloaded for const char* to
invoke the constructor of std::string, meaning

const string &x = std::string("Hallo");

So - tell me, why doesn't the lifespan of the *actual* string end in
that same line, leaving x to be a dangling reference?
I'm not entirely sure, but according to Stroustrup: "A temporary
created to hold a reference initializer persists until the end of its
reference's scope" (The C++ Programming Language, Pg 98). This is why
the lifespan doesn't end on the same line.

As for the first case, I'm not so sure, but I'll try to guess. You
were passing a temporary object to another function which was
receiving it in a reference parameter. Because the reference was not
visible in the original scope of the temporary, the temporary object
ceased to exist at the end of the expression.
Nov 19 '07 #5
Marco Manfredini schrieb:
const string __tmpval = std::string("Hallo");
const string &x = __tmpval;
Alright, I get that.

What I'm not getting, however: consider the following:

#include <vector>
#include <iostream>

class a {
public:
const std::string &foo;
a(const std::string &bar) : foo(bar) { };

void show() {
std::cerr << "String: '" << foo << "'" << std::endl;
};
};

int main() {
a xyz = a(std::string("Das ist ein Test!"));
xyz.show();

return 0;
}

Here are four possible ways to declare foo/bar (&foo, foo, &bar, bar).
The problem is: it doesn't matter what the constructor declaration of
"bar" looks like, only the *implementation* knows if the object in
question is copied or referenced (i.e. it depends on the declaration of
"foo").

This means an "outsider" needs to know if a class will copy or reference
the given constructor parameters (i.e. the implementation), which is not
really that nice. It would be neat if that could be seen just by looking
at the prototype.

Greetings,
Johannes

--
"PS: Ein Realname wäre nett. Ich selbst nutze nur keinen, weil mich die
meisten hier bereits mit Namen kennen." -- Markus Gronotte aka "Makus"
aka "Kosst Amojan" aka "maqqusz" in de.sci.electronics
<45**********************@newsspool3.arcor-online.net>
Nov 19 '07 #6
I'd like to clear something up on this point...

On case number 4, the output is ''. As I understand, on my machine,
technically, the compiler implements the reference as a pointer, and
since the object-referred-to is destroyed, that pointer is set to
NULL. So in the end, I have some equivalent of
std::cout << (char*)NULL;
Which prints nothing.

If this is indeed the way this behaves, is this undefined behavior?
(ie, what is expected of a "danging reference"?)
Nov 19 '07 #7
On Nov 19, 1:29 pm, coder <plcoderREMOVET...@gmail.comwrote:
On Nov 19, 4:13 pm, Johannes Bauer <dfnsonfsdu...@gmx.dewrote:
Marco Manfredini schrieb:
Johannes Bauer wrote:
>So it is clear to me that when using number 3, the
>compiler throws an error - since the created string
>object goes out of scope (and lifespan) immediately after
>the constructor of "a" is called.
No, the compiler throws an error because you are trying to
bind a const reference to a non-const reference. This is
completely unrelated to the lifetime issue.
Oh, okay. Coming from C, I'm not used to a compiler being so
strict on the "const" keyword, but I like it.
The same rules apply in C (except, of course, that C doesn't
have references). You can't assign a pointer to const to a
pointer to non-const in C.

Of course, that wasn't the problem in your original code.
>This seems intriguing. The string is already destroyed,
>however a may keep a reference (moo) to it? How is that
>possible?
References do not protect the referenced object from
destruction - if an objects dies before the reference to
it vanishes, you end up with a "dangling reference". In
that respect, a reference isn't much better that a
pointer.
Okay, that sounds a little bit dangerous - as I thought C++
should guarantee references are always valid (or at least
always not-NULL). Would at least valgrind detect access to
a dangling reference?
Probably, at least if you tried to use it.
Btw. as a certain optimization and a feature to dumbfound
beginners and intermediate users, the following code:
const string &x="Hallo";
cout << x;
Although I don't consider myself to be a greenhorn, this
still dumbfounds me. The assignment operator is overloaded
for const char* to invoke the constructor of std::string,
meaning
There's no assignment operator involved in the above. There is
an implicit conversion of the char const[6] to an std::string.
const string &x = std::string("Hallo");
So - tell me, why doesn't the lifespan of the *actual*
string end in that same line, leaving x to be a dangling
reference?
Because the standard says that it doesn't.
I'm not entirely sure, but according to Stroustrup: "A
temporary created to hold a reference initializer persists
until the end of its reference's scope" (The C++ Programming
Language, Pg 98). This is why the lifespan doesn't end on the
same line.
As for the first case, I'm not so sure, but I'll try to guess.
You were passing a temporary object to another function which
was receiving it in a reference parameter. Because the
reference was not visible in the original scope of the
temporary, the temporary object ceased to exist at the end of
the expression.
In the original code, there were two references: the argument to
the constructor, and the reference in the class. The first was
initialized by the temporary; if it had had a longer lifetime,
then the temporary's lifetime would have been extended. The
second was initialized by another reference, and so can have no
influence on any temporary, anywhere.

Another way of looking at it is to say that the extension of
lifetime is not transitive.

I might add, however, that reference members are a special case
anywhere, and have rules of their own when initialized with a
temporary. The simple rule is: don't.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Nov 19 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: BKDotCom | last post by:
Many built-in functions allow an optional variable to be passed for error messages. How do I implement this in my own function? function test($param1, $param2, &$errormsg) { // complains if 3rd...
3
by: domeceo | last post by:
can anyone tell me why I cannot pass values in a setTimeout function whenever I use this function it says "menu is undefined" after th alert. function imgOff(menu, num) { if (document.images) {...
26
by: Dave Hammond | last post by:
In document "A.html" I have defined a function and within the document body have included an IFRAME element who's source is document "B.html". In document "B.html" I am trying to call the function...
4
by: hello smith | last post by:
I have a lot of functions that add values to an array. They alos update a global variable of type int. Currently, I use a global variable to hold this array. All functions access this array...
3
by: Miguel | last post by:
Hi, I'm new to .NET and am using VB .NET as I am from a VB background. I am having difficulty understanding the way .NET handles, passes and uses objects. I have had a look at the Micrsoft Data...
6
by: ged | last post by:
Hi, i am a oo (c#) programmer, and have not used javascript for a while and i cant work out how javascript manages its references. Object References work for simple stuff, but once i have an...
9
by: zholthran | last post by:
Hi folks, after reading several threads on this issue (-> subject) I fear that I got a problem that cannot easily be solved by the offered workarounds in an acceptable way, at least not with my...
5
by: sfeher | last post by:
Hi All, I need to call a function(loaded with appendChild) for which I have the name as a string. .... var fnName = 'fn1'; var call = fnName + '('+ param +' )'; eval(call);
5
by: aelred | last post by:
I have a web page where a member can open up a chat window (child window) with another member. - From there the member can also navigate to other web pages. - From other pages in the site, they...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.