开发者

How can you modify an object without calling member functions?

开发者 https://www.devze.com 2023-03-14 23:07 出处:网络
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 circumstan

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开发者_如何学JAVA 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?


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.,


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.


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'.


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?


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.


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 */ }


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号