I get a runtime error with the following code, which is a reproducible reduction of my actual code. I am sure I am not instantiating something properly, but I cannot figure out what it is.
#include <iostream>
using namespace std;
class A {
int n;
public:
A();
A(const int k);
int getn() const { return n; };
};
A::A() : n(0) {};
A::A(const int k) : n(k) {}
class B {
const A& myA;
public:
B(const A& anA);
int getn() const { return myA.getn(); };
};
B::B(const A& anA) : myA(anA) {}
class C {
const A& myA;
const B& myB;
public:
C(const A& anA);
int getn() const { return myB.getn(); };
};
C::C(const A& anA) : myA(anA), myB(myA) {}
class D {
A myA;
C myC;
public:
D(const int k);
int getAn() const { return myA.getn(); };
int getCn() const { return myC.getn(); };
};
D::D(const int k) : myA(k), myC(myA) {}
int main() {
D myD(10);
cerr << "A: " << myD.getAn() << '\n';
cerr << "C: " << myD.getCn() << '\n';
}
I either get a segmentation fault on the second line of output or "C:0", instead of "C:10" which I expect.
The problem is in this line:
C::C(const A& anA) : myA(anA), myB(myA) {}
myB is a reference. But to what? The answer is to a temporary. myB(myA) will construct a temp object that is assigned to your reference. Unfortunately this object will be destroyed after the Ctor exits.
Change your code to the following:
class C {
const A& myA;
const B myB;
public:...
and it should work.
BTW: I nearly always declare constructors with one argument as explicit. Do so and the compiler will warn you.
You are trying to initialize D::myC with reference to D::myA, this is not correct because object is not completely constructed at this moment.
D::D(const int k) : myA(k), myC(myA) {}
Related
Having this code:
#include <iostream>
#include <vector>
#include <string>
class A{
public:
A(std::string const& name) : name(name) {}
std::string const& getName() const {
return name;
}
private:
std::string name;
};
class B{
public:
void add(A const& a){
//vec.emplace_back(a) does not help either
vec.push_back(a);
}
std::vector<A> const& getVec() const {
return vec;
}
private:
std::vector<A> vec;
};
class C{
public:
C(B const& b, A const& a) : a(a), b(b) {}
A const& getA() const {
return a;
}
B& getB() {
return b;
}
private:
A a;
B b;
};
class D{
public:
C& add(C& c){
A const& a = c.getA();
B& b = c.getB();
b.add(a);
vec.push_back(c);
return c;
}
private:
std::vector<C> vec;
};
int main(){
A a1{"first"};
A a2{"second"};
B b;
C c1{b, a1};
C c2{b, a2};
D d;
d.add(c1);
d.add(c2);
for(A const& a : b.getVec()){
std::cout << a.getName() << ' ';
}
}
There is no output from the program, but
I would expect output:
first second
Where the B class is holding the vector, and D is trying to modify it (c.getB().add()) via class C. It's just simple example (encountered in a school project), but I wanted to know by this example the flow of changes between classes.
C's members are not reference types. Both c1 and c2 are storing copies of the constructor arguments.
So
d.add(c1);
d.add(c2);
doesn't affect b in main, only the members of c1 and c2, which are copies of the original b, a1 and a2 in main.
The code below is a simplified version of the actual problem I am facing.
Assume I do not have permission to modify class A (as it is external library), and its already widely used in my existing code base.
The const & assignment from a temporary object (direct constructor) which also return a const & member variable via implicit conversion is not valid in this case.
How do I prevent or make it legal in this case so that the caller gets the correct A value?
class A
{
public:
A() { }
A(int _r, int _g, int _b)
: r(_r), g(_g), b(_b)
{
}
~A(){ }
int GetR() const { return r; }
int GetG() const { return g; }
int GetB() const { return b; }
private:
int r = 0;
int g = 0;
int b = 0;
};
class Foo
{
public:
Foo() : Foo(A()) {}
Foo(int _r, int _g, int _b) : a(A(_r, _g, _b)) {}
explicit Foo(const A& _a) : a(_a) {}
Foo& operator=(const A& a)
{
*this = Foo(a);
return *this;
}
operator A() const { return a; }
operator const A&() const { return a; }
private:
A a;
};
int main()
{
const A& a = Foo(200, 100, 300);
std::cout << a.GetR() << a.GetG() << a.GetB() << endl; // I may not get 200 100 300 here as Foo is already out of scope
return 0;
}
Motivation
Some background on why I am implementing a class as above. The actual purpose of class Foo is to contain 2 different objects, which actually has the same purpose, just different way of storing data internally. For example, let's say class A and class B, which stores RGB value of color in int and floating (normalized) respectively. And as mentioned above, I do not have permission to modify class A, and its already widely used in my code base.
There are tons of function in my code base which takes in const A& and const B& as a function param. So I am trying to unify this 2 classes for a particular case, where I can just pass in Foo in those places and it will work as expected.
You can apply ref-qualified member functions (since C++11), i.e. mark the conversion operator with lvalue-reference, to prevent it being called on temporaries (rvalues).
class Foo
{
public:
... ...
operator A() const { return a; }
operator const A&() const & { return a; }
operator const A&() && = delete;
... ...
};
Then
const A& a = Foo(200, 100, 300); // invalid; invokes deleted operator
const A& a = static_cast<A>(Foo(200, 100, 300)); // fine; invokes operator A()
This question already has answers here:
Calling an explicit constructor with a braced-init list: ambiguous or not?
(2 answers)
Closed 2 years ago.
Consider the following little program:
#include <vector>
class A {
int a;
int b;
public:
explicit A() = default;
A(int _a, int _b) : a(_a), b(_b) {}
int f(const A& a) { return 0; }
int f(std::vector<int> a) { return 1; }
};
int g(const A& a) { return 2; }
int g(std::vector<int> a) { return 3; }
int main() {
A a(1,2);
// a.f({}); //ambiguous according to gcc
g({}); //ambiguous according to gcc
return 0;
}
GCC 10.2 refuse to compile it: it says the call to g({}) and a.f({}) are ambiguous. Clang compile this without complaining.
It seems to me that g(const A&) shouldn't be considered in overload resolution because implicit conversion from no arguments is not allowed: A::A() is marked explicit.
I am not confident that the fault isn't mine and, in any case, I'd like to find a workaround.
Is there another default generated constructor that could be the source of my problem?
You can try it on the compiler explorer.
This SO post was brought to my attention. Its answer tells us which compiler is right: it's GCC. But it does not tell us how to obtain the desired behavior with those overload rules.
You're right that it seems like a bug. The commented out line below fails to compile for the exact reason that there should be no ambiguity.
Got a workaround for you using std::initializer_list:
#include <fmt/core.h>
#include <vector>
class A {
int a;
int b;
public:
explicit A() = default;
A(int _a, int _b) : a(_a), b(_b) {fmt::print("Aab\n");}
void f(const A& a) { fmt::print("A\n"); }
void f(std::vector<int> a) { fmt::print("vector\n"); }
void f(std::initializer_list<int> l) {
return f(std::vector<int>(l));
}
};
void g(const A& a) { fmt::print("A\n"); }
void g(std::vector<int> a) { fmt::print("vector\n"); }
void g(std::initializer_list<int> a) {return g(std::vector<int>(a)); }
int main() {
A a(1,2);
A a2 = A();
//A a3 = {};
a.f({});
g({});
return 0;
}
I have class:
class A{
public:
A(int v){
this->v=new int;
*(this->v)=v;
}
~A(){
delete v;
}
A add(A &a, A &b){
A res(0);
*(res.v)=*(a.v)+*(b.v)+*v;
return res;
}
int get(){
return *v;
}
private:
A();
int* v;
void operator=(const A &other);
TreePointer(const A &other);
};
I want to use it as follows:
A finalRes=a.add(b,c).add(a,a);
It works perfectly, there is no any leaks memory.
But how to implement a similar behavior and usage, without using NRVO optimization? What standard design patterns exist for this purpose?
Avoid new, prefer std::unique_ptr instead.
In your case, in fact, you don't even need pointer:
class A{
public:
explicit A(int v) : v(v){}
~A() = default;
void operator=(const A &) = default;
A(const A &) = default;
A add(const A& a, const A& b) const { return A{v + a.v + b.v}; }
int get() const { return v; }
private:
int v;
};
I have this couple of code-lines:
#include <iostream>
using namespace std;
class A
{
public:
A() noexcept
{
cout << "A::A()" << endl;
}
A(const A&) noexcept
{
cout << "A::A(const A&)" << endl;
}
A(A&&) noexcept
{
cout << "A::A(A&&)" << endl;
}
};
class B
{
public:
B(const A& a) noexcept :
_a(a)
{}
B(A&& a) noexcept :
_a(a)
{}
private:
A _a;
};
int main(int argc, char* argv[])
{
A a;
B b1 = B(a);
B b2 = B(A());
}
They produce this output:
A::A()
A::A(const A&)
A::A()
A::A(const A&)
What need I to do in order to the A::A(A&&) will be called from the B::B(A&&)?
As you can see adding noexcept does not solve this issue.
Although the type of a is an rvalue reference to A, a itself is an lvalue. To retain its rvalue-ness, you need to use std::move:
B(A&& a) noexcept :
_a(std::move(a))
{}