472,958 Members | 1,969 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,958 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 5712
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 oriente objet/
Beratung in objektorientierter Datenverarbeitung
9 place Smard, 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: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
3
by: nia12 | last post by:
Hi there, I am very new to Access so apologies if any of this is obvious/not clear. I am creating a data collection tool for health care employees to complete. It consists of a number of...
2
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...

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.