I have question. Let's have this code:
#include <iostream>
#include <string>
#include <memory>
class Writable {
public:
virtual ~Writable() = default;
virtual void write(std::ostream& out) const = 0;
};
class String : public Writable {
public:
String(const std::string& str) : m_str(str) {}
virtual ~String() override = default;
virtual void write(std::ostream& out) const override { out << m_str << '\n'; }
private:
std::string m_str;
};
class Number : public Writable {
public:
Number(double num) : m_num(num) {}
virtual ~Number() override = default;
virtual void write(std::ostream& out) const override { out << m_num << '\n'; }
private:
double m_num;
};
int main() {
std::unique_ptr<Writable> str1(new String("abc"));
std::unique_ptr<Writable> num1(new Number(456));
str1->write(std::cout);
num1->write(std::cout);
}
I dont understand why unique_pointers are defined like this:
std::unique_ptr<Writable> str1(new String("abc"));
Its some kind of shorthand? Or I must do it this way? Is there some kind of equivalent? For example like:
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator.
std::unique_ptr<Writable> str1(new String("abc"));
Here you are creating a new unique_ptr and initializing with a raw pointer returned by new operator and move constructing another unique_ptr with it.
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
However compiler can (most likely) perform move elison and make the above two equivalent.
The right way to initialize from c++14 and later is below
std::unique_ptr<Writable> v1 = std::make_unique<String>();
The form of initialization in
std::unique_ptr<Writable> str1(new String("abc"));
is called direct initialization. If the constructor is marked explicit (like in explicit unique_ptr(pointer p) noexcept constructor), this form of initialization is required.
explicit constructor disables copy initialization in the form of std::unique_ptr<Writable> str1 = new String("abc");.
Just like you can write
std::vector<int> foo(10);
to create a vector of 10 int's
std::unique_ptr<Writable> str1(new String("abc"))
creates a std::unique_ptr<Writable> that points to a new String("abc"). It is the same as doing
std::vector<int> foo = std::vector(10);
and
std::unique_ptr<Writable> str1 = std::unique_ptr<String>(new String("abc"));
except that the later cases use copy initialization which can be different in some cases.
To save on some typing you could use
auto str1 = std::make_unique<String>("abc");
instead when you declare your unique_ptr's
Related
I have a class that needs to grab an environment variable and use it in various processing. It should be const. My understanding of constness is that it must be instantiated on initialization. So something like this would work
class C
{
public:
C() : idFromEnv(getenv("ENV")) {}
private:
std::string idFromEnv;
};
But that isn't a safe way of doing it because an exception will be thrown if the string is null. I thought there might be a way of incorporating ternary operators to do this.
Something like this, but this is really ugly:
class C
{
public:
C() : idFromEnv(getenv("ENV") ? getenv("ENV") : "UNKNOWN")
{
std::cout << idFromEnv << "\n";
}
private:
const std::string idFromEnv;
};
I'm not using that. Anyone have any more elegant suggestions?
Based on suggestions, I tried this. It does work. Not quite what I had in mind.
class C
{
public:
inline const std::string getEnvString(const char *env)
{
char* cStr = getenv(env);
return(std::string(cStr ? cStr : "UNKNOWN"));
}
C() : idFromEnv(getEnvString("ENV"))
{
std::cout << idFromEnv << "\n";
}
private:
const std::string idFromEnv;
};
You might also consider using a default member initializer.
So instead of writing it in the constructor, you would add a default value for idFromEnv:
class C
{
public:
C() = default;
private:
std::string idFromEnv = getenv("ENV") ? getenv("ENV") : "UNKNOWN";;
};
My understanding of constness is that it must be instantiated on initialization.
There is no const issues in the 1st example you present, so there is no need to initialize idFromEnv in the constructor's initialization list if you don't want to. You can assign it in the constructor's body instead, eg:
class C
{
public:
C()
{
char* cStr = getenv("ENV");
idFromEnv = cStr ? cStr : "UNKNOWN";
}
private:
std::string idFromEnv;
};
But, if idFromEnv needs to be const, then yes, you have to initialize it in the constructor's initialization list instead. So using a helper function to wrap the extra getenv() handling is really your best option, eg:
std::string getenvstr(const char *env)
{
char* cStr = getenv(env);
return cStr ? cStr : "UNKNOWN";
}
class C
{
public:
C() : idFromEnv(getenvstr("ENV")) {}
private:
const std::string idFromEnv;
};
Suppose I have this struct
struct MyStruct {
static MyStruct Create(int x) {
return { x*2, x>3 };
}
MyStruct(const MyStruct& c) = delete; // no copy c'tor
private:
MyStruct(int a_, bool b_) : a(a_), b(b_) {} // private c'tor -- can't use new
const int a;
const bool b;
};
Edit: I deleted the copy constructor. This is simplified example of some classes I have in my codebase where they don't have copy c'tors.
I can get an instance on the stack like so:
int main() {
auto foo = MyStruct::Create(2);
return 0;
}
But suppose I need a pointer instead (or unique_ptr is fine), and I can't change the implementation of MyStruct, how can I do that?
You could wrap MyStruct in another class, which has a MyStruct member. Here's a minimal version of that:
class Wrapper {
public:
MyStruct ms;
Wrapper(int x) : ms(MyStruct::Create(x)) { }
};
which you can use like so:
int main() {
MyStruct::Create(2);
std::make_unique<Wrapper>(2);
}
This code will not trigger any copies nor moves - because of copy elision (see: What are copy elision and return value optimization?).
You can then add any other constructors and methods you like to such a wrapper, possibly forwarding some of the method calls to the ms member. Some might choose to make ms protected or private.
Is this what you're looking for?
auto baz = std::make_unique<MyStruct>( MyStruct::Create(2) ); // unique pointer
A comment rather than an answer, to avoid confusion for future readers.
I can get an instance on the stack like so:
int main() {
auto foo = MyStruct::Create(2);
return 0;
}
Note that this is only true as of C++17 and guaranteed copy elision, whereas the program is ill-formed is C++14, as even if the copy may be elided, the initialization of foo is copy-initialization from a temporary (in C++17: the temporary is never materialized).
One more way to do it:
struct ChildStruct : public MyStruct {
ChildStruct(int x) : MyStruct(MyStruct::Create(x))
{}
};
int main() {
MyStruct *foo1 = new ChildStruct(2);
return 0;
}
C style solution. I am not sure that this is not UB, but for simple struct with 2 integer fields it should work.
int main() {
auto foo = MyStruct::Create(2);
MyStruct *p = (MyStruct*)malloc(sizeof(MyStruct));
memcpy(p, &foo, sizeof(MyStruct));
//...
free(p);
return 0;
}
I've narrowed down my problem to exactly this
#include <iostream>
#include <functional>
struct Foo {
std::function<Foo*()> lambda;
Foo()
:lambda([this](){return this;})
{}
};
int main(){
Foo a;
Foo b = a;
std::cout << &a << " " << a.lambda() << std::endl;
std::cout << &b << " " << b.lambda() << std::endl;
}
where the output is
0x7ffd9128b8a0 0x7ffd9128b8a0
0x7ffd9128b880 0x7ffd9128b8a0
I originally expected that this would always point to the instance that owned the lambda. However I forgot about copy construction. In this case the lambda captures this and then it is fixed and no matter how many times the lambda is copied it points to the original value of this.
Is there a way fix this so that lambda always has a reference to it's owning object this even under copy construction of the owning object.
Sounds like you need to provide your own special member functions, no? E.g., for the copy constructor:
Foo(const Foo& other)
:lambda([this](){return this;})
{}
Whilst #lubgr answered the question for what I asked I think it is worth noting the other solution I have for my exact problem. The question stemmed from building a class to encapsulate lazy initialisation of members. My original attempt was
template <typename T>
class Lazy {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
std::function<T()> _factory;
void Init() const { boost::call_once([&] { _data = _factory(); }, _once); }
public:
explicit Lazy(std::function<T()> factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value() {
Init();
return *_data;
}
};
which can be used like
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([this](){return this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value();
but has the same problem that I asked in my question in that this is a circular reference that doesn't get preserved for copy construction. The solution is not to create a custom copy constructor and possibly move constructor but to fix the Lazy implementation class so that we can pass in an arg to the factory.
The new implementation of Lazy for members is
template <typename T, typename TThis>
class LazyMember {
mutable boost::once_flag _once;
mutable boost::optional<T> _data;
typedef std::function<T(TThis const*)> FactoryFn;
FactoryFn _factory;
void Init(TThis const * arg0) const { boost::call_once([&] { _data = _factory(arg0); }, _once); }
public:
explicit LazyMember(FactoryFn factory):_once(BOOST_ONCE_INIT),_factory(factory){}
T& Value(TThis const * arg0) { Init(arg0); return *_data; }
T const & Value(TThis const * arg0) const { Init(arg0); return *_data; }
};
which is used as
class Foo {
int _a;
Lazy<int> _val;
Foo(a):_a(a):_val([](Foo const * _this){return _this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value(&f);
and this doesn't have the circular reference problems and thus doesn't require a custom copy/move constructor.
Consider this code:
#include <iostream>
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 ); // Normal case, nothing new.
const test t2( txt2 ); // Since object is const, I'd like to be able to pass a const argument in.
}
It blows up with the error:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
const test t2( txt2 );
Then I tried to add a second constructor to test whether the compiler could select the right one for t2, my const object:
test( const char *arg )
: _arg( arg )
{}
but then the error is:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
: _arg( arg )
So declaring my object as const does not make its fields const as well.
How to properly declare my class constructors so that it can handle const and non-const object creation?
How to properly declare my class constructors so that it can handle const and non-const object creation?
The object isn't const during construction, or the constructor wouldn't be able to initialize the object (since all data members would be const).
So, constructors can't be const-qualified and you can't have a constructor overload used for const objects.
Now, you can overload on the argument, but your data member always has type char * during construction, although it's qualified to char * const (not const char *) when used in a const-qualified instance of test.
Options are:
overload constructor on argument type, and store a char * always. If you're passed a const char * you have to copy it (and you're responsible for knowing that you own and must deallocate this memory)
In this scheme, you rely on keeping the pointer private and using const-qualified accessors to stop the contents of the pointer being changed via a const-qualified object.
Again, you need to do this manually because char * const is a different type than const char *, because constness of the pointed-to type isn't related to constness of the pointer: having a const instance of your class just stops you mutating the pointer, not the characters it points to.
overload constructor and store a const char * always. This avoids copying but obviously doesn't work if you sometimes need to change the pointed-to characters
just write different mutable-string and immutable-string classes
If it helps, consider this:
template <typename T> struct test {
T* p_;
test(T *p) : p_(p) {}
};
template <typename T> test<T> mktest(T *p) { return {p}; }
and note that
const char *ccp = "immutable characters in a string literal";
char *cp = strdup(ccp);
auto a = mktest(ccp);
auto b = mktest(cp);
gives a the type test<const char>, and b the type test<char> and that these types are not the same, are not convertible, and are no more closely related in the language than to test<T> for any other type T.
A note: this is a long answer for a use case that might be a bad design. Yet, the reason and the main focus for the long answer is:
to show and explain what is not possible
to present a way in which one can make the compiler decide based on the constness of a parameter whether to create a holding const object and to preserve this information even if the object is passed on. Which is very close to the OP request.
As explained in other answers, you can have two constructors, one for const parameter and the other for non-const, but both constructors would just create an object that can be either const or non-const. So this doesn't help.
Another approach could be to have a factory method that would create either a const object or a non-const, according to the constness of the parameter. Though this may sound promising it would not allow to preserve the semantics of the difference between the two, as shown in the following pseudo code:
// creating an object holding a const, using the factory method `create`:
const MyClass const_holder = create(const_param);
// however you cannot prevent this:
MyClass non_const_holder = create(const_param);
The factory would create in the second case above a const object that would be copied or moved (or just created directly as non_const_obj with copy elision, since C++17 as mandatory copy elision). You cannot do anything to avoid the second case unless you delete copy and move, in which case the first case wouldn't work also and the all thing collapses.
So, without creating actually two different types it is impossible to preserve the information of which constructor was used and to avoid assignment of an object created with const param into an object that doesn't.
However, there is no real need to bother the user with the fact that there are two classes, with a proper template implementation the user can have simple code that gives the feeling that there is only one class in the game, something like:
// creating a const holder with a factory method
// the type would *remember* that it is holding a const resource
// and can act accordingly
auto const_holder = create(const_param);
// and you can also create a non const holder with the same factory
auto non_const_holder = create(param);
These operations would be allowed:
// (a) calling a non const method on the content of the non const holder
non_const_holder->non_const_method();
// (b) assigning a non const holder into a const holder object
// -- same as assigning char* to const char*
const_holder = non_const_holder;
These operations would NOT be allowed:
// (a) calling a non const method on the content of a const holder
const_holder->non_const_method(); // should be compilation error
// (b) assigning a const holder into a non const holder object
// -- same as one cannot assign const char* to char*
non_const_holder = const_holder; // should be compilation error
In a way, this is very similar to the idea of propagate_const...
The code would have a factory method:
template<class T>
Pointer<T> create(T* t) {
return Pointer<T>::create(t);
}
And two implementations for the template class Pointer.
base template:
template<class T>
class Pointer {
T* ptr;
Pointer(T* p) : ptr(p) {}
friend class Pointer<const T>;
public:
// factory method
static Pointer create(T* p) {
return p;
}
operator T*() { return ptr; }
operator const T*() const { return ptr; }
};
and a specialized one for the const version:
template<class T>
class Pointer<const T> {
const T* ptr;
Pointer(const T* p) : ptr(p) {}
public:
Pointer(const Pointer<T>& other) {
ptr = other.ptr;
}
// factory method
static const Pointer create(const T* p) {
return p;
}
operator const T*() { return ptr; }
operator const T*() const { return ptr; }
};
The main would look like:
int main() {
char str[] = "hello";
const char* const_str = "hello";
// non-const - good!
auto s1 = create(str);
// const holding non-const - ok!
const auto s2 = create(str);
// non-const that holds const - good!
auto s3 = create(const_str);
// also possible: const holding const
const auto s4 = create(const_str);
s1[4] = '!'; // OK
// s2[0] = '#'; // obviously doesn't compile - s2 is const
// s3[0] = '#'; // doesn't compile - which is good - s3 holds const!
// s4[0] = 'E'; // obviously doesn't compile - s4 is const
// avoids assignment of s3 that holds a const into s1 that holds a non-const
// s1 = s3; // <= doesn't compile - good!
s3 = s1; // allows assignment of `holding-non-const` into `holding-const`
s3 = s2; // allows assignment of `holding-non-const` into `holding-const`
s3 = s4; // allows assignment of `holding-const` into `holding-const`
}
Code: http://coliru.stacked-crooked.com/a/4729be904215e4b2
The problem you experience goes a bit deeper. It's an indication of a design issue.
You would like to expose only part of the API. You say that for a const object you will call only const methods and for non-const you can do anything. But this is problematic.
Either you accept const object strip it from const qualifier, and won't call non-const methods by a silent contract. Or, you need to limit methods, which makes a different object - type-wise.
C# library does it by providing a limited interface which wraps around original object and exposes only const methods. Something like this:
#include <iostream>
using namespace std;
struct A {
void f1() const {cout << "foo\n"; }
void f2() {cout << "bar\n"; }
};
struct readonlyA {
readonlyA(const A& a) : _a(a) {};
void f1() const {_a.f1();};
private:
const A& _a;
};
int main() {
A a;
readonlyA roA(a);
a.f2();
roA.f1();
roA.f2(); // error
return 0;
}
It's basically a read-only proxy.
The compiler does not care about what you actually do with the object at runtime.
Const works because the compiler will forbid certain things at compile time that could potentially change the object. This might be over-restrictive in certain situations, as the compiler often does not have the full picture of what's going on in the program.
Take for example the invocation a non-const member function on a const object: Even if the member function does not actually change the object's state, the compiler will still forbid it because the non-const function could potentially change the object.
Similar in your example: Even though you don't change the member for that particular const instance of the class, there could be other non-const instances of the same class somewhere, which is why it will refuse construct any instance of the class from a const object.
If you want a class that is guaranteed to leave its members unchanged, that would be a different type:
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
class immutable_test
{
public:
immutable_test(char const* arg)
:_arg(arg)
{}
char const* _arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 );
immutable_test t2( txt2 );
}
It can't be done. Just because the object is const, it doesn't mean that it guarantees the char* won't be used to modify its value. The constructor can mutate the argument, and code outside the class can modify its content if it is exposed. Consider the following example.
struct Test {
char* buffer;
Test(char* buffer):
buffer(buffer)
{
buffer[0] = 'a';
}
char* get() const {
return buffer;
}
};
int main(int argc, char* argv[]) {
std::string s{ "sample text" };
const Test t(s.data());
t.get()[1] = 'b';
t.buffer[2] = 'c';
std::cout << s << '\n';
}
The above prints abcple text, even though t is const. Even though it never modifies its members, it does change the pointed-to string and it allows outside code to modify it, too. This is why const objects cannot accept const char* arguments to initialize their char* members.
The compiler is preventing you from carelessly discarding the constness...
class test
{
public:
test(const char *arg)
: _arg(arg)
{}
const char *_arg;
};
Interesting.
Look at the example below (object myclass2) to learn how a const object does not necessarily provide the protection that you need!
#include <iostream>
#include <cctype>
#include <cassert>
class MyClass
{
public:
MyClass(char * str1, size_t size1) : str{str1}, size{size1}
{
}
char * capitalizeFirstChar()
{
*str = std::toupper(*str);
return str;
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
char * str;
size_t size;
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// UGLY!!! const_cast
const MyClass myclass2(const_cast<char *>(str2), sizeof(str2) / sizeof(*str2));
// myclass2.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
myclass2.str[0] = 'Z'; // WILL COMPILE (!!) and should cause a segfault
// The const myclass2, CANNOT PROTECT THE OBJECT POINTED TO by str
// Reason: the member in MyClass is
// char *str
// not
// const char *str
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Ok, the str member issue is actually best solved, by just making the members private.
But what about that ugly const_cast?
One way of solving this is splitting into a Const baseclass, and deriving for non-const behaviour (working with const-casts). Like this perhaps:
#include <iostream>
#include <cctype>
#include <cassert>
class MyClassConst
{
public:
MyClassConst(const char * str1, size_t size1) : str{str1}, size{size1}
{
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
const char * str;
size_t size;
};
class MyClass : public MyClassConst
{
public:
MyClass(char * str1, size_t size1) : MyClassConst{const_cast<const char *>(str1), size1}
{
}
char * capitalizeFirstChar()
{
char * cp = const_cast<char *>(str);
*cp = std::toupper(*cp);
return cp;
}
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// NICE: no more const_cast
const MyClassConst myclass2(str2, sizeof(str2) / sizeof(*str2));
// a.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
// myclass2.str[0] = 'Z'; // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Is it worth it? Depends.
One is kindof trading the const-cast outside of the class... for const-cast inside the class. So maby for library code (including ugly internals, and static code analysis exceptions), with clean outside usage, it's a match...
In the following code example, I want to initialize std::string A::str_ in A's initializer list with either the return value from a function (that may return NULL), or a const char*. But I don't like the fact that Func() is called twice.
#include <iostream>
const char* Func()
{
char* p = NULL;
// Assign p: may be NULL or non-NULL
return p;
}
class A
{
public:
A() : str_( Func() ? Func() : "NULL" ) {}
std::string str_;
};
int main( int argc, char* argv[] )
{
A a;
std::cout << a.str_ << std::endl;
return 0;
}
I would like to do something like this:
A() : str_( ( const char*& tmp = Func() ) ? tmp : "NULL" ) {}
But using temporary variables - even references, to lengthen their lifespan - in this manner seems illegal (per my current understanding).
Is there C++03 syntax that would allow for the initialization of A::str_ in the initializer list, calling Func() only once, and without the use of global/static variables? If there is a solution that uses temporary variables, I would like to learn its syntax.
in C++11, use delegate constructor
class A
{
private:
A(const char* s) str_(s ? s : "NULL") {}
public:
A() : A(Func()) {}
std::string str_;
};
In c++03, create a function helper
class A
{
private:
static const char* FuncNotNull() { const char* s = Func(); return s ? s : "NULL"); }
public:
A() : str_(FuncNotNull()) {}
std::string str_;
};
Here a solution in which a lambda expression is "abused":
A() : str_( ([]()->const char*{ const char* p=Func(); return (p ? p : "NULL"); })() ) {}
I actually voted for Jarod's answer.
But I find the lambda thing that ugly that I wanted to show it as well :-)