lazy initialisation with shared pointer

Hi

I am trying to introduce a lazy initialisation using a shared pointer.
The function that performs the initialisation is a public member function and uses a lambda.

I am unsure if the lambda is correct though. A compile error is generated on the code.

A small subset of the code looks something like this:
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
#include <iostream>
#include <memory>
#include <string>
#include <mutex>

class Member;

using sharep = std::shared_ptr<Member>;

class Member {
  private:
    std::string sname;
    int sage{0};
    std::once_flag once_flag;

  public:
    Member(std::string & name, int age) :  sname{name}, sage{age}  { }
    Member() {}

    Member ( const Member & ) = delete; // avoid copy


    ~Member() {}
    void init_profile(const std::string & name, const int age) {
      sname = name;
    }

    const std::string view_profile() const {
      return "Name : " + sname + ", age: " + std::to_string(sage) ;
    }

    void init(sharep & sptr, const std::string & name, const int age ) {
      std::call_once(once_flag, [sharep & sptr](){ if(!sptr) sptr.reset(new Member); } )
      sptr->init_profile(name, age);
    }
};

int main() {
  sharep sptr;
  sptr.init(sptr, "Harry Potter", 12);
  std::cout << "Profile : " << sptr->view_profile() << "\n";

  return 0;
}


The compile error is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lazy_init_thread_safe02.cpp: In member function ‘void Member::init(sharep&, const string&, int)’:
lazy_init_thread_safe02.cpp:33:34: error: capture of non-variable ‘using sharep = class std::shared_ptr<Member>’
       std::call_once(once_flag, [sharep & sptr](){ if(!sptr) sptr.reset(new Member); } )
                                  ^~~~~~
lazy_init_thread_safe02.cpp:8:39: note: ‘using sharep = class std::shared_ptr<Member>’ declared here
 using sharep = std::shared_ptr<Member>;
                                       ^
lazy_init_thread_safe02.cpp:33:41: error: expected ‘,’ before ‘&’ token
       std::call_once(once_flag, [sharep & sptr](){ if(!sptr) sptr.reset(new Member); } )
                                         ^
lazy_init_thread_safe02.cpp:34:7: error: expected ‘;’ before ‘sptr’
       sptr->init_profile(name, age);
       ^~~~
lazy_init_thread_safe02.cpp: In function ‘int main()’:
lazy_init_thread_safe02.cpp:41:8: error: ‘using sharep = class std::shared_ptr<Member> {aka class std::shared_ptr<Member>}’ has no member named ‘init’
   sptr.init(sptr, "Harry Potter", 12);
        ^~~~
Compilation failed.


Could anybody suggest where the code needs modification ?
Last edited on
std::call_once(once_flag, [/*sharep*/ & sptr](){ if(!sptr) sptr.reset(new Member); } ) ; //missing semicolon http://en.cppreference.com/w/cpp/language/lambda (see lambda capture)


But then on line 40 you do
sptr->init(sptr, "Harry Potter", 12); //dereference the pointer
sptr is a null pointer at that time. don't derefence null pointers.

Hi ne555
Thanks for the reply.

No compile error appears now, but
a runtime "segmentation fault" occurs instead, with the modified code:

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
#include <iostream>
#include <memory>
#include <string>
#include <mutex>

class Member;
using sharep = std::shared_ptr<Member>;

class Member {
  private:
    std::string sname;
    int sage{0};
    std::once_flag once_flag; // std::once_flag cannot be copied or moved

  public:
    Member(const std::string & name, int age) :  sname{name}, sage{age}  { }
    Member() {}
    Member ( const Member & ) = delete; // avoid copy
    ~Member() {}

    void init_profile(const std::string & name, const int age) {
      sname = name;  sage = age;
    }

    const std::string view_profile() const {
      return "Name : " + sname + ", age: " + std::to_string(sage);
    }

    void init(sharep & sptr, const std::string & name, const int age ) {
      std::call_once(once_flag, [/*sharep*/ & sptr](){ if(!sptr) sptr.reset(new Member); } ) ;
      sptr->init_profile(name, age);
    }
};

int main() {
  sharep sptr;
  sptr->init(sptr, "Harry Potter", 12);
  std::cout << "Profile : " << sptr->view_profile() << "\n";
  return 0;
}
Again,
sptr->init(sptr, "Harry Potter", 12);
Will cause UB because sptr is empty.
Last edited on
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
#include <iostream>
#include <memory>
#include <string>
#include <mutex>

class Member;
using sharep = std::shared_ptr<Member>;

class Member {
  private:
    std::string sname;
    int sage{0};
    std::once_flag once_flag; // std::once_flag cannot be copied or moved

  public:
    Member(const std::string & name, int age) :  sname{name}, sage{age}  { }
    Member() {}
    Member ( const Member & ) = delete; // avoid copy
    ~Member() {}

    void init_profile(const std::string & name, const int age) {
      sname = name;  sage = age;
    }

    const std::string view_profile() const {
      return "Name : " + sname + ", age: " + std::to_string(sage);
    }

    void init(sharep & sptr, const std::string & name, const int age ) {
      std::call_once(once_flag, [/*sharep*/ & sptr](){ if(!sptr) sptr.reset(new Member); } ) ;
      sptr->init_profile(name, age);
    }
};

int main() {
	sharep sptr(new Member()); // you missed this line
	sptr->init(sptr, "Harry Potter", 12);
	std::cout << "Profile : " << sptr->view_profile() << "\n";
	return 0;
}
Last edited on

Hi blongho,

many thanks. I'm only a beginner C++ coder, but slowly making my way through C++ Concurrency in Action by Anthony Williams.
The above code is simply a test case I've created in order to try out some of his discussion on pages 60-63.


one small change,

I modified line 36, from this:
sharep sptr(new Member());
to this:
sharep sptr = std::make_shared<Member>();
so no lazy initialization then.
Topic archived. No new replies allowed.