Howard Hinnant in a talk highly recommended implementing each special member function individually and not implement one in terms of the other. For performance, he also discouraged the use of the copy-and-swap idiom in the assignment operator, which is similar to the first option shown in the question (C(std::vector<std::string> s) : _s(std::move(s)) {}
). Such an unified assignment operator can accept both rvalues and lvalues. That is true for this constructor also.
He shows empirical evidence based on a class containing a vector (just like in the question). Especially, if the vector in the target has sufficient capacity, copy-and-swap based assignment can be eight times slower than a dedicated assignment operator. Thus, in the case of C(std::vector<std::string> s) : _s(std::move(s)) {}
accepting an rvalue, there will be unnecessary moving of the rvalue to the parameter s
(which is an lvalue) and it is definitely not desirable.
Thus, separate constructors for lvalue and rvalue arguments are needed. In the case of lvalue being passed, whether the copying should happen at the constructor parameter stage or in the initialization list could be profiled and found out. However, passing an lvalue argument as reference to const lvalue is idiomatic and similar to what a copy constructor would do.
Update: HolyBlackCat has addressed the scalability of the design, which is very important. One more way to achieve it is via parameter pack based forwarding references. However, one should be careful about the pitfall of such a constructor superseding other constructors and one should constrain the template using SFINAE or concepts (C++20). Items 25, 26 and 27 of Effective Modern C++ by Scott Meyers discusses about these aspects.
Update: In the comments below, Brian Bi has raised the question "How costly is the move that you are trying to save?", when you prefer
C(const std::vector<std::string> &s) : _s(s) {}
C(std::vector<std::string>&& s) : _s(std::move(s)) {}
to
C(std::vector<std::string> s) : _s(std::move(s)) {}
Indeed, the extra move incurred by pass-by-value is not an issue for several types. Thus, being mindful about the types involved is important. Item 41 of the above book discusses about this debate between the two choices, more generally, not just for constructors. Some guidelines from that book:
... use overloading or universal references instead of pass by value
unless it's been demonstrated that pass by value yields acceptably
efficient code for the parameter type that you need.
... for software that must be as fast as possible, pass by value may
not be a viable strategy ...
The last point is alluded to in HolyBlackCat's answer also.