13

At 3.10/10, the standard says:

An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]

So, rvalues are non-modifiable except under certain circumstances. We're told that calling a member function is one of those exceptions. This gives the idea that there are ways of modifying objects other than calling a member function. I can't think of a way.

How can one modify an object without calling a member function?

5
  • 10
    Would writing a field of the object be considered modifying it? Commented Jun 24, 2011 at 10:37
  • 1
    (This came out of stackoverflow.com/questions/6466253/…) Commented Jun 24, 2011 at 10:40
  • With great difficulty. For one, you can't use functions since you can't get a mutable ref through the call. Commented Jun 24, 2011 at 10:41
  • @Martinho: Did you mean "This gives the idea that you can't modify an object without calling a member function" Commented Jun 24, 2011 at 10:42
  • @Sasha, well yes, of course that would be modification. (How could I forget that?) Commented Jun 24, 2011 at 10:44

7 Answers 7

3

How can one modify an object [that's specified by an rvalue expression] without calling a member function?

I know of only one way to do that, namely to bind the object to a reference to const, and then cast away the const-ness.

E.g.

template< class Type >
Type& tempRef( Type const& o ) { return const_cast< Type& >( o ); }

struct S { int x; };

int main()
{ tempRef( S() ).x = 3; }

This is because a temporary object is not const itself unless it is of const type, so the example above does not cast away original const-ness (which would be UB).

EDIT, added: Luc Danton’s answer showed another (non-general) way, namely where the temporary's construction stores some reference or pointer to the object in some accessible location.

Cheers & hth.,

Sign up to request clarification or add additional context in comments.

1 Comment

"This is because a temporary object is not const itself unless it is of const type", that's only guaranteed to be the case in C++0x though - should be mentioned.
2

This seems to be accepted:

struct T {
   int x;
};

int main() {
   T().x = 3;
}

I am slightly surprised that this works, because IIRC the LHS of op= must be an lvalue, yet the following implies that even T().x is an rvalue:

struct T {
   int x;
};

void f(int& x) {
   x = 3;
}

int main() {
   f(T().x);
}

Edit: As of 4.6, GCC does warn about T().x = 3: error: using temporary as lvalue.

I can't think of any other way to modify a class object other than through data member access or member function calls. So, I'm going to say... you can't.

16 Comments

g++ says error: using temporary as lvalue [-fpermissive] on the line T().x = 3;.
@Fred: what flags are you using? g++ -Wall -Wextra -pedantic gives me no output on the first example.
It is additionally possible to modify objects of appropriate types through e.g. std::memset but since this needs a pointer it cannot be applied to rvalues either.
@Alf: That famous copy assignment operator for int.
@DeadMG: Not by default. You need --std=c++0x for that.
|
1

Modifying a temporary and not through an lvalue to that temporary:

#include <cstring>

class standard_layout {
    standard_layout();
    int stuff;
};

standard_layout* global;

standard_layout::standard_layout()
{ global = this; }

void
modify(int)
{
    std::memset(global, 0, sizeof *global);
}

int
main()
{
    modify( (standard_layout {}, 0) );
}

I don't think it's correct to assume that rvalues of class types are non-modifiable. I now understand that paragraph as 'for non-class types, an lvalue for an object is needed in order to modify that object'.

6 Comments

Yet that's what the standard says in 3.10/10. Aren't you using an lvalue here? Or is it pertinent that the object was originally seen as an rvalue? Argh!
@Tomalak global as it appears in the call to memset is an lvalue, but not an lvalue for the object being modified (that would be *global), as appears in the paragraph.
@Luc: Hmm ok. Presumably, though, at some point memset is using *global.
@Tomalak I believe a memset that uses char pointers would be conforming (and, well, plain obvious) and *(char*)this is not an lvalue for *this.
@Luc: No lvalue-to-rvalue conversion for "use"?
|
0

I can think of one way:

If your class exposes public member variables, you can assign directly to those member variables. For example:

class A
{
    public:
        int _my_var;
...
};

int main(int argc, char** argv)
{
    A *a = new C();
    a->_my_var = 10;
}

This is not a good programming style though - exposing a member variable as public isn't something I would advocate or even suggest.

Also, if you can do something really weird, such as directly writing some address in memory, an offset from the pointer to the class object - but why would you do that?

3 Comments

I would put this as a comment if I could
"Also, if you can do something really weird, such as directly writing some address in memory, an offset from the pointer to the class object" How? The temporary ceases to exist before you get a chance, and it has no memory address.
What does this answer have to do with rvalues?
0

How can one modify an object without calling a member function?

By assigning a value to one of the object's visible data members, of course.

Comments

0

Doing an implicit cast is sort of like calling a member function -- also modifying rvalue refs seems to work.

Tested the following in vc++10 and g++ 4.4.

struct b { int i; b(int x) : i(x) {} };
struct a { int i; a() : i(0) { } operator b() { return i++ /* this works */, b(i); } };
a f(a&& x) { return x.i++ /* this works */, x; }
int main() { b b = f(a()); /* implicit operator b() cast; b.i will equal 2 */ }

Comments

-1

A member function can change the member directly, but it can also delegate that responsibility:

struct Foo {
  int x;
  void Bar() { scanf("%d", &x); }
};

The current wording of the standard has the advantage that one doesn't need to argue whether this is a case of Bar changing the object. If we'd agree that scanf changes the object, then that's just another example.

1 Comment

Huh, you're calling a member function. And we don't need to argue whether this is a case of Bar changing the object because it does, not because of any wording in the standard. You're taking a non-const pointer to a member.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.