0

For a class containing a vector of strings, suppose we want a constructor which can either pass in a list or a single value. How can the second constructor call the first in an initializer list?

class A {
private:
  std::vector<const char*> paths;
public:
  A(std::vector<const char*>& paths) : paths(paths) {}
  A(const char* p) : A(std::vector<const char*>( { p } ) {}
};

The second constructor is not legal. I can't think of the syntax.

A(const char* p) : A( {p} ) {}

Not that either.

Dov
  • 8,000
  • 8
  • 46
  • 75

1 Answers1

1

You are creating a temporary vector, thus you should use a const reference in your first constructor:

class A {
private:
  std::vector<const char*> paths;
public:
  A(const std::vector<const char*>& paths) : paths(paths) {}
  A(const char* p) : A(std::vector<const char*>{ p }) {}
};

Alternatively, think about using r-value reference:

class A {
private:
  std::vector<const char*> paths;
public:
  A(std::vector<const char*>&& paths) : paths(std::move(paths)) {}
  A(const char* p) : A(std::vector<const char*>{ p }) {}
};
lukeg
  • 4,189
  • 3
  • 19
  • 40
  • @1201ProgramAlarm how about take by value and move? Isn't that more idiomatic? It also helps with exception safety since any exception that copying may throw happens in the context of the calling code, not your constructor. – Aykhan Hagverdili Jun 20 '20 at 16:59
  • @_Static_assert: by value allows to misuse it and doing extra copy. IMO, by r-value reference is better. By r-value reference also allow to handle strong guaranty exception, whereas by value already consume input. – Jarod42 Jun 20 '20 at 19:30
  • @jarod42 in which condition does by value incur an extra copy? R-value causes code duplication as you need to overload for an l-value reference also. And by what measures does it give you a better exception guarantee? – Aykhan Hagverdili Jun 20 '20 at 19:37
  • @_Static_assert: User might pass l-value :( forgetting to use `std::move`, I create table in [another answer](https://stackoverflow.com/questions/61597860/taking-sink-parameters-by-rvalue-reference-instead-of-by-value-to-enforce-perfor/61601352#61601352) to show copy/move count about the different way to pass parameters. – Jarod42 Jun 20 '20 at 19:52
  • @_Static_assert: About exception guaranty, it is also debatable :/ by value sinks immediately, so if other parts of the function(constructor) throw, you have already consume input and cannot restore it. (for strong exception guaranty). Passing by r-value allows to handle that (manually). But, indeed, by value move the "dangerous" part (the one which might throw) in caller side, doing only the move (which is more inclined to be `nothrow`) in the function/constructor. – Jarod42 Jun 20 '20 at 20:01
  • @Jarod42 if you're overloading with a const l-value reference, forgetting to use `std::move` means that constructor is going to do the extra copy, so I don't see the benefit there. Are you suggesting to have a single r-value constructor? That seems a bit inconvenient to use. – Aykhan Hagverdili Jun 20 '20 at 20:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/216338/discussion-between-jarod42-and-staticassert). – Jarod42 Jun 20 '20 at 20:55