can vectors be used without invoking copy constructor?

Jul 14, 2019 at 3:12am
Hi

I have a vector V which contains objects of type O. Generally, I want to prevent O from being copied so I've made the copy/assignment operators private.

On doing this, I've been getting compiler errors and I'm pretty sure that these relate to V which contains elements of typo O. I assume that V invokes O's copy constructor when using push_back and erase etc which explains the compiler errors.

Is there anyway to make O uncopyable but allow O to be used in V? I think move constructors might be helpful here but I'm not sure.

Thanks
Jul 14, 2019 at 4:28am
> Is there anyway to make O uncopyable but allow O to be used in V? I think move constructors might be helpful here

Yes. Make it moveable.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <string>
#include <fstream>
#include <type_traits>
#include <vector>

struct A // moveable, but non_copyable
{
    A() = default ;
    explicit A( const std::string& path ) : file(path) {}
    explicit A( std::ofstream&& stm ) : file( std::move(stm) ) {}

    bool can_write() const { return file.is_open() && file ; }

    std::ofstream file ;
    // copy constructor and copy assignment operator are implicitly deleted
};

int main()
{
    std::cout << std::boolalpha
              << "copy constructible? " << std::is_copy_constructible<A>::value << '\n'
              << "copy assignable? " << std::is_copy_assignable<A>::value << '\n'
              << "move constructible? " << std::is_move_constructible<A>::value << '\n'
              << "move assignable? " << std::is_move_assignable<A>::value << "\n\n" ;

    std::vector<A> vec ;
    vec.emplace_back( "123.txt" ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.emplace_back( "456.txt" ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.resize(7) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    vec.emplace_back( std::ofstream( "789.txt" ) ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;

    {
        A a( "abcd.txt" ) ;
        vec.push_back( std::move(a) ) ; // don't use the moved from a after this
        std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << '\n' ;
    }

    vec.erase( vec.begin()+3, vec.begin()+6 ) ;
    std::cout << "size: " << vec.size() << " capacity: " << vec.capacity() << "\n\n" ;

    for( const A& a : vec ) std::cout << a.can_write() << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/51654a0f25cd8b78
https://rextester.com/LHWCA6840
Jul 14, 2019 at 2:49pm
// copy constructor and copy assignment operator are implicitly deleted
Is that because std::ofstream has deleted copy constructor/assignment operator?

In general, you'd prevent A from being copied by deleting the copy constructor and assignment operator, right?
1
2
3
4
5
6
struct A {
    A();
    A(const A&) = delete;
    const A& operator=(const A&) = delete;
    int i;
};




Jul 14, 2019 at 5:05pm
> Is that because std::ofstream has deleted copy constructor/assignment operator?

Yes.


> In general, you'd prevent A from being copied by deleting the copy constructor
> and assignment operator, right?

Yes. In that case, the rule of five would apply.

Because the presence of a user-defined destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator, any class for which move semantics are desirable, has to declare all five special member functions
https://en.cppreference.com/w/cpp/language/rule_of_three#Rule_of_five
Last edited on Jul 14, 2019 at 5:05pm
Topic archived. No new replies allowed.