0

I was just saw code like this

/* whatever */ foo(std::string const& s) {
  // stuff
  auto L = s.length();
  int i{/* init based on L */};
  while (i < L) {
    // do other stuff and maybe
    ++i;
  }
}

and I was going to suggest that one can avoid defining L and write /* init based on s.length() */ and (i < s.length()) instead of /* init based on L */ and (i < L).

But who's really telling me that s.length() doesn't change unpredictably because the argument corresponding to the s parameter is changed by another concurrent thread?

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • 1
    You don't need a thread. What if `//do other stuff` indirectly calls a function that modified whatever `s` refers to. – StoryTeller - Unslander Monica Jan 26 '23 at 11:01
  • Well, but in some way I know my function, so at least I could verify that I'm not doing it. whereas whether a thread modified `s` is out of my control. – Enlico Jan 26 '23 at 11:02
  • 1
    There are various kinds of thread unsafety. The reference is const with respect to this function but this might not be true somehwere else in the code (e.g. other threads may still have modifiable access). So reading still would need to be protected by a mutex in that case. Then there is the lifecycle aspect, if not designed properly the object the reference refers to might be deleted by the time you want to use it. So no const doesn't guarantee anything. – Pepijn Kramer Jan 26 '23 at 11:03
  • You know your function? And every other function it calls from every library? Through every potential CB and use case? Impressive. – StoryTeller - Unslander Monica Jan 26 '23 at 11:04
  • @Enlico No that's the wrong way of thinking. You can't look at threading issues with only a local view. Threading must be designed into a project, you need to be able to specifiy up front which code must be threadsafe, and how long objects lifetimes will be. E.g. objects must live longer then the threads that use them or a thread must be able to extend the lifetime of an object (e.g. shared ownership/std::shared_ptr). – Pepijn Kramer Jan 26 '23 at 11:05
  • @StoryTeller-UnslanderMonica, I think `foo`'s body can be made dumb/toy enough to be sure I know it (say `int i{}`, no `// do other stuff`, and finally `return i;`). But as I'm understanding from yours and Pepijn's comments, as dumb as I make it, I can never tell what happens do to the environment where `foo` is used. – Enlico Jan 26 '23 at 11:08

1 Answers1

3

No, nobody could possibly tell you that. This is a common misunderstanding of what a const object means.

A const object is not a promise that some other execution thread can't modify the object, while you go about your business.

A const object is a promise that the code that accesses the const object cannot modify it (whatever "modify" means for the object in question).

In fact, no other execution thread needs to be involved, at all. This foo function, in the "stuff" part, can call some other function that has access, via some pointer or reference somewhere, the exact same const object and completely change it inside and out, then return to this foo function.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148