template<class Y>
operator auto_ptr_ref<Y>() throw() {
return auto_ptr_ref<Y>(release());
}
It is part of implementation of class auto_ptr in standard library.
What does this means to do?
Why there is an "auto_ptr_ref" between "operator" and "()"?
I'll tell you why that conversion operator happens to be there. Well, look at this example:
struct A;
struct B {
explicit B(A&a):a(a){ }
A &a;
};
struct A {
A() { }
A(B b){ move_from(a); }
A(A &a) { move_from(a); }
operator B() { return B(*this); }
void move_from(A &a) {
std::cout << "A::A(#" << &b.a << ")" << std::endl;
}
};
int main() {
A a = A();
}
We have move semantics for our class A: In its copy constructor, we want to "steal" away some stuff from the other instance. For auto_ptr, that is the pointer that is managed, for us we just output a message instead. What is important is that we can't use a usual copy constructor:
A(A const& a) {
/* oops, a is const, we can't steal something from it! */
}
But if we change that to A(A &a), we won't be able to construct from a by-value/temporary A: Those can't be bound to a reference-to-nonconst:
A(A &a) {
}
...
A a = A(); // fail, because A &a = A() doesn't work
auto_ptr and our A class uses the trick that non-const member functions can still be called on temporaries/by-value A's. That is, we could also have written:
struct A {
...
B get_b() { return B(*this); }
...
};
...
A a = A().get_b();
But that works, we don't want to be bothered with that, of course. We want that it just works to assign a A() or the return value of a function returning an A by-value. So what auto_ptr and our A class uses is a conversion operator, which automatically figures out that when A is converted to B, then we could construct a A instance using the B we created temporarily.
That is the conversion operator in action, casting from auto_ptr to auto_ptr_ref<Y>.
Related
I'm recently learning about move constructor, and I met a strange problem.
I have the following code:
#include <iostream>
class a
{
public:
a() { printf("default\n"); }
a(const a& aa) { printf("const lr\n"); }
a(a& aa) { printf("lr\n"); }
a(a&& aa) { printf("rr\n"); }
a(const a&& aa) { printf("const rr\n"); }
};
a foo()
{
return a();
}
void func(a& a) {
printf("func lr\n");
}
void func(a&& aa) {
printf("func rr\n");
}
int main()
{
printf("a1: ");a a1;
printf("a2: ");a a2(a1);
printf("a3: ");a a3(std::move(a2));
printf("a4: ");a a4(foo());
printf("a5: ");a a5(std::move(foo()));
func(foo());
}
The output is:
a1: default
a2: lr
a3: rr
a4: default
a5: default
rr
default
func rr
All is good except for a4. I expect that the return type of foo() is a rvalue. I think the call of func() at last has proved that. So why doesn't the move constructor called when constructing a4? And at the same time, it is called when constructing a5.
That's probably because of copy_elision.
Under the following circumstances, the compilers are required to omit
the copy- and move- construction of class object:
In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue:
T f() { return T{}; }
T x = f(); // only one call to default constructor of T, to initialize x
T* p = new T(f()); // only one call to default constructor of T, to initialize *p
Your situation falls under the second case.
Assume I have a class with different constructors:
class A
{
public:
A(char* string)
{
//...
}
A(int value)
{
//..
}
void check() {}
};
Now I want to create an A object on stack, the constructor must be choosed depending on some condition, but there is a problem: the created object is destroyed then we quit {...} block.
bool isTrue() { /*...*/ }
int main()
{
if (isTrue())
{
A a("string");
}
else
{
A a(10);
}
a.check(); //error: 'a' is not defined in this scope
}
Suppose I haven't the copy-constructor or operator= in the A class. So how can solve this issue?
http://ideone.com/YsjmnK
A a = isTrue() ? A("string") : A(10);
And if a.check() is a const member function, an alternative may be better:
const A& a = isTrue() ? A("string") : A(10);
The object will be destroyed when the reference a go out of scope.
Note since C++17, according to the rule of copy elision the copy/move constructor is not required to be accessible for this case; copy elision is guaranteed here.
And since C++17 you can use std::optional, which doesn't cause any dynamic memory allocation. e.g.
std::optional<A> a;
if (isTrue())
{
a.emplace("string");
}
else
{
a.emplace(10);
}
(*a).check();
BTW: A(char* string) is supposed to be A(const char* string).
You can't satisfy all your stated requirements.
If you can get rid of the requirement for the object to be on stack, you could use a pointer.
A *a;
if (isTrue())
a = new A("string");
else
a = new A(10);
a->check();
delete a;
If the type has a default constructor, you can default-construct an object, immediately destruct it, and then construct it again with the appropriate constructor via placement-new:
A a;
a.~A();
if (isTrue())
{
new(&a) A("string");
}
else
{
new(&a) A(10);
}
The C++ standard has several examples similar to the above, just search for .~ and ->~.
Note that this is ultra evil. If your code ever gets reviewed, you are probably going to get fired.
I had the exact same question a while ago and this is what google helped me find:
unique_ptr<A> foo;
if(isTrue())
foo = std::unique_ptr<A>(new A("10"));
else
foo = std::unique_ptr<A>(new A(10));
Its probably too late for the OP but someone else might hopefully find this useful.
You can use the template class:
template<class type> class A
{
protected:
type T;
public:
void A(type t_curr) {T = t_curr;};//e.g.---
void check() {}
};
Recently I have read that it makes sense when returning by value from a function to qualify the return type const for non-builtin types, e.g.:
const Result operation() {
//..do something..
return Result(..);
}
I am struggling to understand the benefits of this, once the object has been returned surely it's the callers choice to decide if the returned object should be const?
Basically, there's a slight language problem here.
std::string func() {
return "hai";
}
func().push_back('c'); // Perfectly valid, yet non-sensical
Returning const rvalues is an attempt to prevent such behaviour. However, in reality, it does way more harm than good, because now that rvalue references are here, you're just going to prevent move semantics, which sucks, and the above behaviour will probably be prevented by the judicious use of rvalue and lvalue *this overloading. Plus, you'd have to be a bit of a moron to do this anyway.
It is occasionally useful. See this example:
class I
{
public:
I(int i) : value(i) {}
void set(int i) { value = i; }
I operator+(const I& rhs) { return I(value + rhs.value); }
I& operator=(const I& rhs) { value = rhs.value; return *this; }
private:
int value;
};
int main()
{
I a(2), b(3);
(a + b) = 2; // ???
return 0;
}
Note that the value returned by operator+ would normally be considered a temporary. But it's clearly being modified. That's not exactly desired.
If you declare the return type of operator+ as const I, this will fail to compile.
There is no benefit when returning by value. It doesn't make sense.
The only difference is that it prevents people from using it as an lvalue:
class Foo
{
void bar();
};
const Foo foo();
int main()
{
foo().bar(); // Invalid
}
Last year I've discovered another surprising usecase while working on a two-way C++-to-JavaScript bindings.
It requires a combination of following conditions:
You have a copyable and movable class Base.
You have a non-copyable non-movable class Derived deriving from Base.
You really, really do not want an instance of Base inside Derived to be movable as well.
You, however, really want slicing to work for whatever reason.
All classes are actually templates and you want to use template type deduction, so you cannot really use Derived::operator const Base&() or similar tricks instead of public inheritance.
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
// Simple class which can be copied and moved.
template<typename T>
struct Base {
std::string data;
};
template<typename T>
struct Derived : Base<T> {
// Complex class which derives from Base<T> so that type deduction works
// in function calls below. This class also wants to be non-copyable
// and non-movable, so we disable copy and move.
Derived() : Base<T>{"Hello World"} {}
~Derived() {
// As no move is permitted, `data` should be left untouched, right?
assert(this->data == "Hello World");
}
Derived(const Derived&) = delete;
Derived(Derived&&) = delete;
Derived& operator=(const Derived&) = delete;
Derived& operator=(Derived&&) = delete;
};
// assertion fails when the `const` below is commented, wow!
/*const*/ auto create_derived() { return Derived<int>{}; }
// Next two functions hold reference to Base<T>/Derived<T>, so there
// are definitely no copies or moves when they get `create_derived()`
// as a parameter. Temporary materializations only.
template<typename T>
void good_use_1(const Base<T> &) { std::cout << "good_use_1 runs" << std::endl; }
template<typename T>
void good_use_2(const Derived<T> &) { std::cout << "good_use_2 runs" << std::endl; }
// This function actually takes ownership of its argument. If the argument
// was a temporary Derived<T>(), move-slicing happens: Base<T>(Base<T>&&) is invoked,
// modifying Derived<T>::data.
template<typename T>
void oops_use(Base<T>) { std::cout << "bad_use runs" << std::endl; }
int main() {
good_use_1(create_derived());
good_use_2(create_derived());
oops_use(create_derived());
}
The fact that I did not specify the type argument for oops_use<> means that the compiler should be able to deduce it from argument's type, hence the requirement that Base<T> is actually a real base of Derived<T>.
An implicit conversion should happen when calling oops_use(Base<T>). For that, create_derived()'s result is materialized into a temporary Derived<T> value, which is then moved into oops_use's argument by Base<T>(Base<T>&&) move constructor. Hence, the materialized temporary is now moved-from, and the assertion fails.
We cannot delete that move constructor, because it will make Base<T> non-movable. And we cannot really prevent Base<T>&& from binding to Derived<T>&& (unless we explicitly delete Base<T>(Derived<T>&&), which should be done for all derived classes).
So, the only resolution without Base modification here is to make create_derived() return const Derived<T>, so that oops_use's argument's constructor cannot move from the materialized temporary.
I like this example because not only it compiles both with and without const without any undefined behaviour, it behaves differently with and without const, and the correct behavior actually happens with const only.
I want to enforce explicit conversion between structs kind of like native types:
int i1;
i1 = some_float; // this generates a warning
i1 = int(some_float): // this is OK
int i3 = some_float; // this generates a warning
I thought to use an assignment operator and copy constructor to do the same thing, but the behavior is different:
Struct s1;
s1 = other_struct; // this calls the assignment operator which generates my warning
s1 = Struct(other_struct) // this calls the copy constructor to generate a new Struct and then passes that new instance to s1's assignment operator
Struct s3 = other_struct; // this calls the COPY CONSTRUCTOR and succeeds with no warning
Are there any tricks to get that third case Struct s3 = other_struct; construct s3 with the default constructor and then call the assignment operator?
This all compiles and runs as it should. The default behavior of C++ is to call the copy constructor instead of the assignment operator when you create a new instance and call the copy constructor at once, (i.e. MyStruct s = other_struct;becomes MyStruct s(other_struct); not MyStruct s; s = other_struct;. I'm just wondering if there are any tricks to get around that.
EDIT: The "explicit" keyword is just what I needed!
class foo {
foo(const foo& f) { ... }
explicit foo(const bar& b) { ... }
foo& operator =(const foo& f) { ... }
};
foo f;
bar b;
foo f2 = f; // this works
foo f3 = b; // this doesn't, thanks to the explicit keyword!
foo f4 = foo(b); // this works - you're forced to do an "explicit conversion"
Disclaimer: I'm ready to take the downvotes on this, since this doesn't answer the question. But this could be useful to the OP.
I think it is a very bad idea to think of the copy constructor as default construction + assignment. It is the other way around:
struct some_struct
{
some_struct(); // If you want a default constructor, fine
some_struct(some_struct const&); // Implement it in the most natural way
some_struct(foo const&); // Implement it in the most natural way
void swap(some_struct&) throw(); // Implement it in the most efficient way
// Google "copy and swap idiom" for this one
some_struct& operator=(some_struct x) { x.swap(*this); return *this; }
// Same idea
some_struct& operator=(foo const& x)
{
some_struct tmp(x);
tmp.swap(*this);
return *this;
}
};
Implementing things that way is fool proof, and is the best you can obtain in term of conversion semantics in C++, so it is the way to go here.
You can get around this if you overload the type cast operator for other_struct, and edit the original structure accordingly. That said, it's extremely messy and there generally isn't a good reason to do so.
#include <iostream>
using namespace std;
struct bar;
struct foo {
explicit foo() {
cout << "In foo default constructor." << endl;
}
explicit foo(bar const &) {
cout << "In foo 'bar' contructor." << endl;
}
foo(foo const &) {
cout << "In foo constructor." << endl;
}
foo const & operator=(bar const &) {
cout << "In foo = operator." << endl;
return *this;
}
};
struct bar {
operator foo() {
cout << "In bar cast overload." << endl;
foo x;
x = *this;
return x;
}
};
int main() {
bar b;
foo f = b;
return 0;
}
Outputs:
In bar cast overload.
In foo default constructor.
In foo = operator.
In foo constructor.
In foo constructor.
In short, no.
The long version...actually that's about it. That's just not how it works. Had to come up with something to fill the character requirement though.
I don't think so. When you write
Struct s3 = other_struct;
It looks like an assignment, but really it's just declarative syntax that calls a constructor.
Sorry for the basic question, but I'm having trouble finding the right thing to google.
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
delete x;
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
It looks like it does the assignment correctly, then calls the destructor on obj1 leaving x with a garbage value rather than a value of 4. If this is valid, why does it do this?
If there is a class C that has a constructor that takes an int, is this code valid?
C obj1(3);
obj1=C(4);
Assuming C has an operator=(C) (which it will by default), the code is valid. What will happen is that in the first line obj1 is constructed with 3 as a the parameter to the constructor. Then on the second line, a temporary C object is constructed with 4 as a parameter and then operator= is invoked on obj1 with that temporary object as a parameter. After that the temporary object will be destructed.
If obj1 is in an invalid state after the assignment (but not before), there likely is a problem with C's operator=.
Update: If x really needs to be a pointer you have three options:
Let the user instead of the destructor decide when the value of x should be deleted by defining a destruction method that the user needs to call explicitly. This will cause memory leaks if the user forgets to do so.
Define operator= so that it will create a copy of the integer instead of a copy of the value. If in your real code you use a pointer to something that's much bigger than an int, this might be too expensive.
Use reference counting to keep track how many instances of C hold a pointer to the same object and delete the object when its count reaches 0.
If C contains a pointer to something, you pretty much always need to implement operator=. In your case it would have this signature
class C
{
public:
void operator=(const C& rhs)
{
// For each member in rhs, copy it to ourselves
}
// Your other member variables and methods go here...
};
I do not know enough deep, subtle C++ to explain the problem you are encountering. I do know, however, that it's a lot easier to make sure a class behaves the way you expect if you follow the Rule of Three, which the code you posted violates. Basically, it states that if you define any of the following you should define all three:
Destructor
Copy constructor
Assignment operator
Note as well that the assignment operator implementation needs to correctly handle the case where an object is assigned to itself (so-called "self assignment"). The following should work correctly (untested):
#include <iostream>
#include <string>
using namespace std;
class C {
public:
C(int n) {
x = new int(n);
}
C(const C &other): C(other.getX()) { }
~C( ) {
delete x;
}
void operator=(const C &other) {
// Just assign over x. You could reallocate if you first test
// that x != other.x (the pointers, not contents). The test is
// needed to make sure the code is self-assignment-safe.
*x = *(other.x);
}
int getX() {return *x;}
private:
int* x;
};
void main( ) {
C obj1 = C(3);
obj1 = C(4);
cout << obj1.getX() << endl;
}
Basically you are trying to re-implement a smart pointer.
This is not trivial to get correct for all situations.
Please look at the available smart pointers in the standard first.
A basic implementation (Which will fail under certain situations (copy one of the standard ones to get a better one)). But this should cover the basics:
class X
{
int* data;
public:
// Destructor obvious
~X()
{
delete data;
}
// Easy constructor.
X(int x)
:data(new int(x))
{}
// Copy constructor.
// Relatively obvious just do the same as the normal construcor.
// Get the value from the rhs (copy). Note A class is a friend of
// itself and thus you can access the private members of copy without
// having to use any accessor functions like getX()
X(X const& copy)
:data(new int(copy.x))
{}
// Assignment operator
// This is an example of the copy and swap idiom. This is probably overkill
// for this trivial example but provided here to show how it is used.
X& operator=(X const& copy)
{
X tmp(copy);
this->swap(tmp);
return this;
}
// Write a swap() operator.
// Mark it is as no-throw.
void swap(X& rhs) throws()
{
std::swap(data,rhs.data);
}
};
NEW:
What's happening is that your destructor has deallocated the memory allocated by the constructor of C(4). So the pointer you have copied over from C(4) is a dangling pointer i.e. it still points to the memory location of the deallocated memory
class C {
public:
C(int n) {
x = new int(n);
}
~C( ) {
//delete x; //Don't deallocate
}
void DeallocateX()
{
delete x;
}
int getX() {return *x;}
private:
int* x;
};
int main(int argc, char* argv[])
{
// Init with C(3)
C obj1 = C(3);
// Deallocate C(3)
obj1.DeallocateX();
// Allocate memory and store 4 with C(4) and pass the pointer over to obj1
obj1 = C(4);
// Use the value
cout << obj1.getX() << endl;
// Cleanup
obj1.DeallocateX();
return 0;
}
Be explicit about ownership of pointers! auto_ptr is great for this. Also, when creating a local don't do C obj1 = C(3) that creates two instances of C and initializes the first with the copy constructor of the second.
Heed The Guru.
class C {
public:
C(int n) : x(new int(n)) { }
int getX(){ return *x; }
C(const C& other) : x(new int(*other.x)){}
C& operator=(const C& other) { *x = *other.x; return *this; }
private:
std::auto_ptr<int> x;
};
int main() {
C obj1(3);
obj1 = C(4);
std::cout << obj1.getX() << std::endl;
}
When are you testing the value of obj1? Is it after you leave the scope?
In your example, obj1 is a stack object. That means as soon as you leave the function in which it defined, it gets cleaned up (the destructor is called). Try allocating the object on the heap:
C *obj1 = new C(3);
delete obj1;
obj1 = new C(4);