ndbd
ndbd

Reputation: 2549

C++14: How to design setters?

Let's say I have a rather large class A where there is a member of another class B:

class A {
    various large data members here
}


class B {
    public:
      setA( .... );
    private:
       A a;
}

What's the best (both in terms of speed but also code cleanliness) to write the setter for the Amember in B?

First option would be typical C++98 style:

void setA(const A& a) { this.a = a; }

and using it like

B b;
A a;
b.setA(a);

This needs at least one copy, which could be costly. More efficient for large objects would probably a pointer:

class B {
    public:
      setA( .... );
    private:
       A *a;
}

setA(A *a) { this->a = a; }

and

B b;
A *a = new A();
b.setA(a);

This comes with all the nastiness of pointers, having to write custom destructors etc. In C++14 one could use std::uniuqe_ptr, but still this is way less cleaner than simply having a non-pointer member of A in B.

In C++14 there might be the option of using rvalues and move semantics with simple call by value, i.e.

void setA(A a) { this.a = std::move(a); }

and calling it like this:

B b;
A a;
b.setA(std::move(a));  // if we don't need a anymore

This is nice and clean and should be fast, but:

Herb Sutter arguments in his slides on Back to the Basics! Essentials of Modern C++ Style that you should usually prefer

void setA(const A& a) { this.a = a; } 

but he talks in his presentation about a rather small member (a string), so for larger, more complex objects, this might not apply...

What is the proper way of doing it (In Java, this so easy...)

Upvotes: 0

Views: 182

Answers (2)

paler123
paler123

Reputation: 976

You can have two setters, one for rvalue refferences, the other for const&, like this:

void setA(const A& a) { a_ = a; } 
void setA(A&& a) { a_ = std::move(a); }

Or, if you don't intend to use setA with any other types you could use universal refference:

template<typename T>
void setA(T&& a_) { a_ = std::forward<T>(a); }

But since you already allow setting the value, you might as well consider making it public, so that you don't have to worry at all about the setters.

Upvotes: 1

bencemeszaros
bencemeszaros

Reputation: 606

Your object should be ready to use after construction. Why don't pass class A during the construction of class B?

#include <memory>

class A
{
public:
    A(int a) : a{ a } {}
private:
    int a;
};

class B
{
public:
    B(int b, A a) : b{ b }, a{ std::make_unique<A>(a) } {}
private:
    int b;
    std::unique_ptr<A> a;
};

int main()
{
    B b(int{ 4 }, A{ 1 });
}

Upvotes: 1

Related Questions