Is this valid and moral C++?

  • Thread starter Filimon Roukoutakis
  • Start date
F

Filimon Roukoutakis

Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

ie does f() internally actually have read/write access to the Object
allocated in g() on the heap? If not, what would be the trick to achieve
this? Thanks,

filimon
 
G

Gianni Mariani

Filimon said:
Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

ie does f() internally actually have read/write access to the Object
allocated in g() on the heap? If not, what would be the trick to achieve
this? Thanks,

Yes, it is valid.

Objects allocated by new are available to any function before delete is
called on it.
 
D

David Harmon

On Sun, 18 Mar 2007 21:09:22 +0100 in comp.lang.c++, Filimon Roukoutakis
Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

No. The function should receive the pointer argument by value. i.e.
f(Object* obj)

It is invalid to try to pass a modifiable reference to the result of
..back() , and while a const reference would work it has no particular
advantage.

Secondly, your global vector of Object* will NOT delete the objects
pointed to when it's destructor runs at the end of the program. There's
no big deal about reclaiming the memory at that point, but if Object's
destructor does anything else important you've got a problem.
ie does f() internally actually have read/write access to the Object
allocated in g() on the heap?

Yes. In fact that is the only way of accessing the object that you have
left yourself at this point, which is fine.
 
G

Gianni Mariani

David said:
On Sun, 18 Mar 2007 21:09:22 +0100 in comp.lang.c++, Filimon Roukoutakis


No. The function should receive the pointer argument by value. i.e.
f(Object* obj)

It is invalid to try to pass a modifiable reference to the result of
.back() , and while a const reference would work it has no particular
advantage.


Why is it "invalid" ?
 
F

Filimon Roukoutakis

David said:
On Sun, 18 Mar 2007 21:09:22 +0100 in comp.lang.c++, Filimon Roukoutakis


No. The function should receive the pointer argument by value. i.e.
f(Object* obj)

It is invalid to try to pass a modifiable reference to the result of
.back() , and while a const reference would work it has no particular
advantage.

I do want to pass a reference to the pointer so the pointer is
modifiable, or more precicely I want to use this pointer in another
context in the program while it is by itself updated by f. Could you
comment on the invalidity of modifiable reference?
Secondly, your global vector of Object* will NOT delete the objects
pointed to when it's destructor runs at the end of the program. There's
no big deal about reclaiming the memory at that point, but if Object's
destructor does anything else important you've got a problem.


Yes. In fact that is the only way of accessing the object that you have
left yourself at this point, which is fine.

ok for the above I knew, it was just a minimal example.

filimon
 
K

Kai-Uwe Bux

David said:
On Sun, 18 Mar 2007 21:09:22 +0100 in comp.lang.c++, Filimon Roukoutakis


No. The function should receive the pointer argument by value. i.e.
f(Object* obj)
Why?

It is invalid to try to pass a modifiable reference to the result of
.back() , and while a const reference would work it has no particular
advantage.

The call f(vec.back()) does not pass anything "to the result of .back()".
What it does is: it initializes the Object*& parameter of f() with the
result of vec.back(), which so happens to be a reference (non-const in case
the non-const version of back() is called). There is nothing invalid about
it, as far as I can see.

E.g., f() could be:

f ( Object* & p_ref ) {
Object * dummy = new Object ();
std::swap( p_ref, dummy );
delete dummy;
}

Then f(vec.back()) would replace the last pointer with a new pointer whose
pointee has been default constructed.

Secondly, your global vector of Object* will NOT delete the objects
pointed to when it's destructor runs at the end of the program. There's
no big deal about reclaiming the memory at that point, but if Object's
destructor does anything else important you've got a problem.

Right: the vector will not do that by itself. So, the OP will have to take
care of deleting the pointers by himself.


[snip]
 
D

David Harmon

On Sun, 18 Mar 2007 22:37:29 +0100 in comp.lang.c++, Filimon Roukoutakis
I do want to pass a reference to the pointer so the pointer is
modifiable, or more precicely I want to use this pointer in another
context in the program while it is by itself updated by f. Could you
comment on the invalidity of modifiable reference?

What does it mean when your code attempts to modify via the reference,
giving in effect:
vec.back() = (some expression);

As I wrote to Gianni, It is forbidden by the standard to bind a
non-const reference to a temporary. This is one case where that rule
probably even makes sense. If you could actually change the value of
vec.back() without resizing the vector, it would break the vector. If
you think you can resize the vector by, for instance, incrementing
vec.back(), it doesn't work that way.
 
D

David Harmon

On Mon, 19 Mar 2007 08:30:34 +1100 in comp.lang.c++, Gianni Mariani
Why is it "invalid" ?

It is forbidden by the standard to bind a non-const reference to a
temporary. This is one case where that rule probably even makes sense.
If you could actually change the value of vec.back() without resizing
the vector, it would break the vector. If you think you can resize the
vector by, for instance, incrementing vec.back(), it doesn't work that
way.
 
D

David Harmon

On Sun, 18 Mar 2007 18:13:46 -0400 in comp.lang.c++, Kai-Uwe Bux
The call f(vec.back()) does not pass anything "to the result of .back()".
What it does is: it initializes the Object*& parameter of f() with the
result of vec.back(), which so happens to be a reference (non-const in case
the non-const version of back() is called). There is nothing invalid about
it, as far as I can see.

Doh! I was confusing the element access front() and back() with the
iterator functions begin() etc. Disregard all.
 
D

David Harmon

On Mon, 19 Mar 2007 08:30:34 +1100 in comp.lang.c++, Gianni Mariani
Why is it "invalid" ?


Doh! I was confusing the element access front() and back() with the
iterator functions begin() etc. Disregard all.
 
D

David Harmon

On Sun, 18 Mar 2007 22:37:29 +0100 in comp.lang.c++, Filimon Roukoutakis
context in the program while it is by itself updated by f. Could you
comment on the invalidity of modifiable reference?

Doh! I was confusing the element access front() and back() with the
iterator functions begin() etc. Disregard all.
 
J

Jim Langston

Filimon Roukoutakis said:
Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

ie does f() internally actually have read/write access to the Object
allocated in g() on the heap? If not, what would be the trick to achieve
this? Thanks,

By your replies to the other posts, I take it you meant

void g() {
vec push_back( new Object );
f( vec[size() - 1] );
}

f( *(vec.end() - 1) );
may also work.

Your question seems to be, g made a new object, can f access that object?
The answer is yes. It would be the same if you did something like:

Object* MyObject = NULL;

f( Object*& obj )
{
// ...
}

Object* g
{
return new Object;
}

int main()
{
MyObject = g();
f( MyObject );
delete( MyObject );
}

You just happen to be storing it in a vector instead of (in thsi case) a
global variable. Once an object is allocated using new all you need is the
pointer to that memory to access the instance, until delete is called on it.
However you happen to get that pointer (global, from a vecotr, a paramter,
whatever).

Incidently, now a days "heap" is commonly called the "free store". I'm not
sure what the standard calls it.

Just make sure you delete the pointer when done.
 
F

Filimon Roukoutakis

Jim said:
Filimon Roukoutakis said:
Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

ie does f() internally actually have read/write access to the Object
allocated in g() on the heap? If not, what would be the trick to achieve
this? Thanks,

By your replies to the other posts, I take it you meant

void g() {
vec push_back( new Object );
f( vec[size() - 1] );
}

f( *(vec.end() - 1) );
may also work.

Your question seems to be, g made a new object, can f access that object?
The answer is yes. It would be the same if you did something like:

Object* MyObject = NULL;

f( Object*& obj )
{
// ...
}

Object* g
{
return new Object;
}

int main()
{
MyObject = g();
f( MyObject );
delete( MyObject );
}

You just happen to be storing it in a vector instead of (in thsi case) a
global variable. Once an object is allocated using new all you need is the
pointer to that memory to access the instance, until delete is called on it.
However you happen to get that pointer (global, from a vecotr, a paramter,
whatever).

Incidently, now a days "heap" is commonly called the "free store". I'm not
sure what the standard calls it.

Just make sure you delete the pointer when done.

My problem is that when I try to delete the pointer inside f I get a
segmentation violation, so I figured that maybe new Object inside g is
stored as a const reference in the vector which cannot be modified
somehow and this produces the problem.
 
D

David Harmon

On Mon, 19 Mar 2007 10:28:48 +0100 in comp.lang.c++, Filimon Roukoutakis
My problem is that when I try to delete the pointer inside f I get a
segmentation violation, so I figured that maybe new Object inside g is
stored as a const reference in the vector which cannot be modified
somehow and this produces the problem.

No. The contents of the vector, in this case the pointers, are fully
modifiable just as you thought. Even if that were not the case, const
pointers can be deleted as long as they came from 'new' to begin with.
I apologize for muddying the waters.

seg violation on deleting usually means either you are trying to delete
the same object twice, or some pointer that was never new'ed, or that
some random memory write elsewhere in the program has corrupted the
heap. Or something along those lines. Can be tricky to track down.
 
I

Ivan Vecerina

: Suppose that we have a function
:
: f(Object*& obj)
:
: and have declared a global std::vector<Object*> vec;
:
: Is it valid to do
:
: void g() {
: vec.push_back(new Object);
: f(vec.back());
: }
:
: ie does f() internally actually have read/write access to the Object
: allocated in g() on the heap? If not, what would be the trick to
achieve
: this? Thanks,

That part is ok. The only problem I see in the above code is
something that hasn't been mentioned yet:
vec.push_back(new Object);
This is not exception-safe: if push_back fails (because it
is unable to allocate a larger block of memory), the newly
allocated object will be leaked.

But this of course will be unrelated to the problem
you described later.
For that, be careful that you do not modify the vector
(e.g. by adding another element) as long as you are
using the reference returned by back().

hth -Ivan
 
R

Roland Pibinger

The only problem I see in the above code is
something that hasn't been mentioned yet:
vec.push_back(new Object);
This is not exception-safe: if push_back fails (because it
is unable to allocate a larger block of memory), the newly
allocated object will be leaked.

Out-of-memory in C++ is usually handled by the new_handler, not with
exception handling. If one really needs to handle OOM with exception
handling vector::reserve() may be called in advance.

Best regards,
Roland Pibinger
 
I

Ivan Vecerina

: On Tue, 20 Mar 2007 07:27:17 +0100, "Ivan Vecerina" wrote:
: >The only problem I see in the above code is
: >something that hasn't been mentioned yet:
: > vec.push_back(new Object);
: >This is not exception-safe: if push_back fails (because it
: >is unable to allocate a larger block of memory), the newly
: >allocated object will be leaked.
:
: Out-of-memory in C++ is usually handled by the new_handler, not with
: exception handling.

What is your definition of "usually" ???
http://www.google.com/codesearch?q=set_new_handler
This gives 2-3'000 hits, many of them being declarations
in library headers. Not quite was I would call "usual".
Plus new_handler is required to either throw an exception,
or terminate the program. Does it really help here ?

: If one really needs to handle OOM with exception
: handling vector::reserve() may be called in advance.

Yes, this is one of several ways to address the problem.
All I am saying is that this issue is worth attention.

Regards,
Ivan
 
F

Filimon Roukoutakis

Filimon said:
Suppose that we have a function

f(Object*& obj)

and have declared a global std::vector<Object*> vec;

Is it valid to do

void g() {
vec.push_back(new Object);
f(vec.back());
}

ie does f() internally actually have read/write access to the Object
allocated in g() on the heap? If not, what would be the trick to achieve
this? Thanks,

filimon

Problem solved. The problem was that the above code produced a
segmentation violation in another part of the program. The fix was to
replace std::vector<Object*> with std::vector<Object**> and
vec.push_back(new Object*). Probably this was not obvious in the context
of the code snippet that was presented here. Thanks for the answers.

filimon
 
J

Jim Langston

Filimon Roukoutakis said:
Problem solved. The problem was that the above code produced a
segmentation violation in another part of the program. The fix was to
replace std::vector<Object*> with std::vector<Object**> and
vec.push_back(new Object*). Probably this was not obvious in the context
of the code snippet that was presented here. Thanks for the answers.

std::vector<someclass*> is usually bad design unless you are working with
polymorphism. Even then some would say use a smart pointer (although I use
naked pointers myself).

std::vector<someclass**> I could only think is bad design. You may want to
relook at what you are doing and see if this is absolutly necessary, it
sounds like a maintainance nightmare.
 
B

Bo Persson

Filimon Roukoutakis wrote:
:: Filimon Roukoutakis wrote:
::: Suppose that we have a function
:::
::: f(Object*& obj)
:::
::: and have declared a global std::vector<Object*> vec;
:::
::: Is it valid to do
:::
::: void g() {
::: vec.push_back(new Object);
::: f(vec.back());
::: }
:::
::: ie does f() internally actually have read/write access to the Object
::: allocated in g() on the heap? If not, what would be the trick to
::: achieve this? Thanks,
:::
::: filimon
::
:: Problem solved. The problem was that the above code produced a
:: segmentation violation in another part of the program. The fix was to
:: replace std::vector<Object*> with std::vector<Object**> and
:: vec.push_back(new Object*).

Agreeing with Jim Langston's post, I can only say that dynamically
allocating a single pointer is EXTREMELY unusual.

In my opinion, it is HIGHLY LIKELY that you have not actually solved the
problem, but only happen to hide it.


Bo Persson
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top