473,854 Members | 1,684 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

[allocator.conce pt] smart pointer clarifications

I am currently writting a smart pointer which is reasonnably stable and I
decided supporting allocators for completion because of its increase in
efficiency when the same pool used by containers is shared. I was told the
new standards are being finalized and I am hoping minor but important
changes could be applied before anything else.

To give a quick overview on the current status of this topic, you will find
below the latest text relating to allocator member functions (n2641). We
see over there there are no dictinction between the pointer type returned by
allocate() and the pointer type expected by deallocate() and destroy().
This is a big problem because this logic doesn't make sense anymore if smart
pointers are to be used. Smart pointers are owners of their objects and
aren't in no way going to give away external access to its object. We need
these functions to use
1) distinct pointer type from the one returned by allocate()
2) make the parameter (pointer) passed as a non-const reference

The latter is necessary to make changes to either the smart pointer itself
or the object pointed to in case raw pointer are used. We can see my
personnal implementation here and I would like to propose the following
function signatures:

template <typename T>
class shifted_allocat or
{
public:
typedef shifted<T value_type;
typedef shifted_ptr<T pointer;
typedef shifted_ptr<con st T const_pointer;

value_type * allocate(size_t ype s, const void * = 0);
void deallocate(poin ter & p, size_type);
void construct(value _type * p, const T & x);
void destroy(pointer & p);
...
};

** Allocator member functions **
1)
pointer X::allocate(siz e_type n);
pointer X::allocate(siz e_type n, const_generic_p ointer hint);

Effects: Memory is allocated for n objects of type value_type but the
objects are not constructed. [Footnote: It is intended that a.allocate be an
efficient means of allocating a single object of type T, even when sizeof(T)
is small. That is, there is no need for a container to maintain its own
"free list". - end footnote] The optional argument, p, may

Returns: A pointer to the allocated memory. [Note: If n == 0, the return
value is unspecified. If n 1, the means by which a program gains access to
the second and subsequent allocated objects is determined outside of the
Allocator concept. See RandomAccessAll ocator, below, for one common
approach. - end note]

Throws: allocate may raise an appropriate exception.

Remark: The use of hint is unspecified, but intended as an aid to locality
if an implementation so desires. [ Note: In a container member function, the
address of an adjacent element is often a good choice to pass for the hint
argument. - end note ]

2)
void X::deallocate(p ointer p, size_type n);

Preconditions: All n value_type objects in the area pointed to by p shall be
destroyed prior to this call. n shall match the value passed to allocate to
obtain this memory. [Note: p shall not be singular. - end note]

Throws: Does not throw exceptions.

3)
void X::destroy(poin ter p);

Effects: Calls the destructor on the object at p but does not deallocate it.

Regards,
-Phil

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.m oderated. First time posters: Do this! ]

Aug 18 '08 #1
13 2084
On Aug 18, 7:28*pm, "Phil Bouchard" <p...@fornux.co mwrote:
I am currently writting a smart pointer which is reasonnably stable and I
decided supporting allocators for completion because of its increase in
efficiency when the same pool used by containers is shared. *I was toldthe
new standards are being finalized and I am hoping minor but important
changes could be applied before anything else.

To give a quick overview on the current status of this topic, you will find
below the latest text relating to allocator member functions (n2641). *We
see over there there are no dictinction between the pointer type returnedby
allocate() and the pointer type expected by deallocate() and destroy().
This is a big problem because this logic doesn't make sense anymore if smart
pointers are to be used. *Smart pointers are owners of their objects and
aren't in no way going to give away external access to its object. *We need
these functions to use
1) distinct pointer type from the one returned by allocate()
2) make the parameter (pointer) passed as a non-const reference

The latter is necessary to make changes to either the smart pointer itself
or the object pointed to in case raw pointer are used. *We can see my
personnal implementation here and I would like to propose the following
function signatures:

template <typename T>
* * class shifted_allocat or
* * {
* * public:
* * * * typedef shifted<T* * * * * * *value_type;
* * * * typedef shifted_ptr<T* * * * *pointer;
* * * * typedef shifted_ptr<con st T* *const_pointer;

* * * * value_type * allocate(size_t ype s, const void * = 0);
* * * * void deallocate(poin ter & p, size_type);
* * * * void construct(value _type * p, const T & x);
* * * * void destroy(pointer & p);
* * * * ...
* * };
[snip]

Perhaps I'm missing something. Smart pointers generally take over
ownership AFTER allocation, e.g.:

tr1::shared_ptr <intspi1( new int(42) );
tr1::shared_ptr <intspi2( FactoryFunction () );

A shared_ptr's deleter can tell it how to do some special release
procedure, e.g.:

tr1::shared_ptr <FILEfile( fopen( "some.txt", "r" ), &fclose );

Why do allocators need to become aware of smart pointers?

Cheers! --M
Aug 19 '08 #2

"mlimber" <ml*****@gmail. comwrote in message
news:e8******** *************** ***********@x35 g2000hsb.google groups.com...

[...]
Perhaps I'm missing something. Smart pointers generally take over
ownership AFTER allocation, e.g.:

tr1::shared_ptr <intspi1( new int(42) );
tr1::shared_ptr <intspi2( FactoryFunction () );

A shared_ptr's deleter can tell it how to do some special release
procedure, e.g.:

tr1::shared_ptr <FILEfile( fopen( "some.txt", "r" ), &fclose );

Why do allocators need to become aware of smart pointers?

Cheers! --M
Well the idea of having of defining an allocator is to centralized in one
class instanciation everything related to memory management. If the
allocator have to be explicitly shared between the container and the smart
pointer itself then the idea becomes pointless. The allocator should be
responsible for all types of deallocations, including smart pointers.
-Phil
Aug 20 '08 #3
On Aug 20, 4:26*am, "Phil Bouchard" <p...@fornux.co mwrote:
"mlimber" <mlim...@gmail. comwrote in message

news:e8******** *************** ***********@x35 g2000hsb.google groups.com...

[...]
Perhaps I'm missing something. Smart pointers generally take over
ownership AFTER allocation, e.g.:
*tr1::shared_pt r<intspi1( new int(42) );
*tr1::shared_pt r<intspi2( FactoryFunction () );
A shared_ptr's deleter can tell it how to do some special release
procedure, e.g.:
*tr1::shared_pt r<FILEfile( fopen( "some.txt", "r" ), &fclose );
Why do allocators need to become aware of smart pointers?

Well the idea of having of defining an allocator is to centralized in one
class instanciation everything related to memory management. *If the
allocator have to be explicitly shared between the container and the smart
pointer itself then the idea becomes pointless. *The allocator should be
responsible for all types of deallocations, including smart pointers.
I still don't get it. Let's say you're designing std::vector, which
has an allocator template parameter. It doesn't matter if the user-
defined class or a smart pointer (as long as it has value semantics).
Given this code:

class C { */...*/ };
// ...
std::vector<Cv1 ( 10 );
std::vector< std::tr1::share d_ptr<C v2( 10 );

Under the hood, each of the latter two lines will use vector's
(default) allocator to grab memory for the 10 instances of the
contained type and then placement-new to construct the instances in
that memory. (Note that all the shared_ptr's pointees are null at this
point.) Why does the allocator care if it's making a C or a
shared_ptr<C>?

Cheers! --M
Aug 20 '08 #4
"mlimber" <ml*****@gmail. comwrote in message
news:b5******** *************** ***********@e53 g2000hsa.google groups.com...
On Aug 20, 4:26 am, "Phil Bouchard" <p...@fornux.co mwrote:

[...]
I still don't get it. Let's say you're designing std::vector, which
has an allocator template parameter. It doesn't matter if the user-
defined class or a smart pointer (as long as it has value semantics).
Given this code:

class C { */...*/ };
// ...
std::vector<Cv1 ( 10 );
std::vector< std::tr1::share d_ptr<C v2( 10 );

Under the hood, each of the latter two lines will use vector's
(default) allocator to grab memory for the 10 instances of the
contained type and then placement-new to construct the instances in
that memory. (Note that all the shared_ptr's pointees are null at this
point.) Why does the allocator care if it's making a C or a
shared_ptr<C>?

Cheers! --M
Indeed in that case it won't matter because the pools used to allocate nodes
from the container and to deallocate objects from the smart pointer are not
shared. Sometimes it is in our favor to share to same pool used by the
container and the smart pointer. For example shifted_ptr<use s this to
prevent cyclicism (still requires STL modifications).

Either we do it this way or we share the allocator across the container and
smart pointer so that the smart pointer uses deallocate(void *):

1)
std::vector<shi fted_ptr<int>, shifted_allocat or<shifted_ptr< int c1;

2)
std::vector<shi fted_ptr<int, shifted_allocat or<int,
shifted_allocat or<shifted_ptr< int, shifted_allocat or<int c2;

I don't even think option 2) is implementable.
-Phil
Aug 20 '08 #5

"Phil Bouchard" <ph**@fornux.co mwrote in message
news:g8******** **@aioe.org...

[...]
The latter is necessary to make changes to either the smart pointer itself
or the object pointed to in case raw pointer are used. We can see my
personnal implementation here and I would like to propose the following
function signatures:

template <typename T>
class shifted_allocat or
{
public:
typedef shifted<T value_type;
typedef shifted_ptr<T pointer;
typedef shifted_ptr<con st T const_pointer;

value_type * allocate(size_t ype s, const void * = 0);
void deallocate(poin ter & p, size_type);
void construct(value _type * p, const T & x);
void destroy(pointer & p);
...
};
[...]

Moreover it turns out this will become an even bigger problem if the new
rule of virtualizing allocator is accepted because the parameters will be
totaly different:

namespace std
{
class allocator_imple mentation
{
typedef void * pointer;

virtual void deallocate(poin ter p, size_type) = 0;
...
};
}

template <typename T>
class shifted_allocat or : std::allocator_ implementation
{
public:
typedef shifted<T value_type;
typedef shifted_ptr<T pointer;
typedef shifted_ptr<con st T const_pointer;

virtual void deallocate(poin ter & p, size_type) // won't override
{
}
...
};

I think the idea of virtualizing the allocators should not be accepted
because it will be irreversible. Correct me if I'm wrong but I don't see
why we couldn't virtualize containers instead. Everybody thinks this means
slower performance but most of today's compilers are smart enough to bypass
the virtual tables. Let's consider the following:

template <typename T>
class list_base : public ...{ /* common operations */ ... };

template <typename T, typename Alloc>
class list : public list_base<T{ ... };
-Phil

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.m oderated. First time posters: Do this! ]

Aug 20 '08 #6
On Aug 20, 12:57*pm, "Phil Bouchard" <p...@fornux.co mwrote:
"mlimber" <mlim...@gmail. comwrote in message

news:b5******** *************** ***********@e53 g2000hsa.google groups.com...
On Aug 20, 4:26 am, "Phil Bouchard" <p...@fornux.co mwrote:

[...]
I still don't get it. Let's say you're designing std::vector, which
has an allocator template parameter. It doesn't matter if the user-
defined class or a smart pointer (as long as it has value semantics).
Given this code:
*class C { */...*/ };
*// ...
*std::vector<Cv 1( 10 );
*std::vector< std::tr1::share d_ptr<C v2( 10 );
Under the hood, each of the latter two lines will use vector's
(default) allocator to grab memory for the 10 instances of the
contained type and then placement-new to construct the instances in
that memory. (Note that all the shared_ptr's pointees are null at this
point.) Why does the allocator care if it's making a C or a
shared_ptr<C>?
Cheers! --M

Indeed in that case it won't matter because the pools used to allocate nodes
from the container and to deallocate objects from the smart pointer are not
shared. *Sometimes it is in our favor to share to same pool used by the
container and the smart pointer. *For example shifted_ptr<use s this to
prevent cyclicism (still requires STL modifications).

Either we do it this way or we share the allocator across the container and
smart pointer so that the smart pointer uses deallocate(void *):

1)
std::vector<shi fted_ptr<int>, shifted_allocat or<shifted_ptr< int c1;

2)
std::vector<shi fted_ptr<int, shifted_allocat or<int,
shifted_allocat or<shifted_ptr< int, shifted_allocat or<int c2;

I don't even think option 2) is implementable.
I may just be dense, but I still don't see what you're getting at.
Can't you just use the deleter parameter to indicate special deletion?
Something like this (untested):

class C { /*...*/ };

template<class Alloc>
class MyDeleter
{
Alloc& m_alloc;

typedef typename Alloc::value_ty pe T;

public:
MyDeleter( Alloc& alloc ) : m_alloc( alloc ) {}

// Might want a const T* version also
void operator()( T* const ptr )
{
m_alloc.destroy ( ptr );
m_alloc.dealloc ate( ptr, sizeof(T) );
}
};

void Foo( MyAllocator<C>& alloc, const C& initVal )
{
typedef std::vector< std::tr1::share d_ptr<C VSPC;
VSPC v( 10 );
for( VSPC::iterator it=v.begin(); it != v.end(); ++it )
{
// Could hide these next lines in a factory function
C* const c = alloc.allocate( sizeof(C) );
alloc.construct ( c, initVal );

it->reset( c, MyDeleter( m_alloc ) );
}
// ...
}

Now, when the vector "v" goes out of scope, the shared_ptrs use the
"alloc" object to deallocate their pointees.

Cheers! --M
Aug 20 '08 #7
mlimber wrote:
template<class Alloc>
class MyDeleter
{
Alloc& m_alloc;

typedef typename Alloc::value_ty pe T;

public:
MyDeleter( Alloc& alloc ) : m_alloc( alloc ) {}

// Might want a const T* version also
void operator()( T* const ptr )
{
m_alloc.destroy ( ptr );
m_alloc.dealloc ate( ptr, sizeof(T) );
}
};
Oops. This won't work as written because of the reference member and
the default copy constructor, but that's easy to fix and you get the
idea.

Cheers! --M
Aug 20 '08 #8

"mlimber" <ml*****@gmail. comwrote in message
news:2e******** *************** ***********@d77 g2000hsb.google groups.com...
On Aug 20, 12:57 pm, "Phil Bouchard" <p...@fornux.co mwrote:
[...]
Either we do it this way or we share the allocator across the container
and
smart pointer so that the smart pointer uses deallocate(void *):

1)
std::vector<shi fted_ptr<int>, shifted_allocat or<shifted_ptr< int c1;

2)
std::vector<shi fted_ptr<int, shifted_allocat or<int,
shifted_allocat or<shifted_ptr< int, shifted_allocat or<int c2;

I don't even think option 2) is implementable.

I may just be dense, but I still don't see what you're getting at.
Can't you just use the deleter parameter to indicate special deletion?
Something like this (untested):

class C { /*...*/ };

template<class Alloc>
class MyDeleter
{
Alloc& m_alloc;

typedef typename Alloc::value_ty pe T;

public:
MyDeleter( Alloc& alloc ) : m_alloc( alloc ) {}

// Might want a const T* version also
void operator()( T* const ptr )
{
m_alloc.destroy ( ptr );
m_alloc.dealloc ate( ptr, sizeof(T) );
}
};

void Foo( MyAllocator<C>& alloc, const C& initVal )
{
typedef std::vector< std::tr1::share d_ptr<C VSPC;
VSPC v( 10 );
for( VSPC::iterator it=v.begin(); it != v.end(); ++it )
{
// Could hide these next lines in a factory function
C* const c = alloc.allocate( sizeof(C) );
alloc.construct ( c, initVal );

it->reset( c, MyDeleter( m_alloc ) );
}
// ...
}

Now, when the vector "v" goes out of scope, the shared_ptrs use the
"alloc" object to deallocate their pointees.
What you are suggesting is very similar to option 2) I was anteriorly
explaining. In my case I was using the allocator passed in as a template
parameter as a deleter so that there is no need to repeatedly call the
overloaded constructor shared_ptr(T *, D *). I can't imagine calling this
special constructor for each node pointer inside a container in a flexible
way. If I forget calling it for one pointer the compiler will not report
any compilation error.
-Phil
Aug 21 '08 #9
On Aug 21, 8:40*am, "Phil Bouchard" <p...@fornux.co mwrote:
"mlimber" <mlim...@gmail. comwrote in message

news:2e******** *************** ***********@d77 g2000hsb.google groups.com...
On Aug 20, 12:57 pm, "Phil Bouchard" <p...@fornux.co mwrote:

[...]
Either we do it this way or we share the allocator across the container
and
smart pointer so that the smart pointer uses deallocate(void *):
1)
std::vector<shi fted_ptr<int>, shifted_allocat or<shifted_ptr< int c1;
2)
std::vector<shi fted_ptr<int, shifted_allocat or<int,
shifted_allocat or<shifted_ptr< int, shifted_allocat or<int c2;
I don't even think option 2) is implementable.
I may just be dense, but I still don't see what you're getting at.
Can't you just use the deleter parameter to indicate special deletion?
Something like this (untested):
* class C { /*...*/ };
* template<class Alloc>
* class MyDeleter
* {
* * Alloc& m_alloc;
* * typedef typename Alloc::value_ty pe T;
* public:
* * MyDeleter( Alloc& alloc ) : m_alloc( alloc ) {}
* * // Might want a const T* version also
* * void operator()( T* const ptr )
* * {
* * * m_alloc.destroy ( ptr );
* * * m_alloc.dealloc ate( ptr, sizeof(T) );
* * }
* };
* void Foo( MyAllocator<C>& alloc, const C& initVal )
* {
* * typedef std::vector< std::tr1::share d_ptr<C VSPC;
* * VSPC v( 10 );
* * for( VSPC::iterator it=v.begin(); it != v.end(); ++it )
* * {
* * * // Could hide these next lines in a factory function
* * * C* const c = alloc.allocate( sizeof(C) );
* * * alloc.construct ( c, initVal );
* * * it->reset( c, MyDeleter( m_alloc ) );
* * }
* * // ...
* }
Now, when the vector "v" goes out of scope, the shared_ptrs use the
"alloc" object to deallocate their pointees.

What you are suggesting is very similar to option 2) I was anteriorly
explaining. *In my case I was using the allocator passed in as a template
parameter as a deleter so that there is no need to repeatedly call the
overloaded constructor shared_ptr(T *, D *). *I can't imagine calling this
special constructor for each node pointer inside a container in a flexible
way. *If I forget calling it for one pointer the compiler will not report
any compilation error.
You said your option 2 was not implementable (perhaps it isn't; my
attempt was a little different). Have I presented a working
implementation supported by the standard and the approved extensions
in TR1 that accomplishes your goal of not having a smart pointer
expose itself for the sake of custom allocators? If so, it seems to me
that no change in the standard libraries is necessary, and authors of
smart pointers just need to model their own smart pointer design on
the standard one (cf. Scott Meyers's explanation of custom deleters:
http://www.artima.com/cppsource/top_..._moments.html).

Moreover, use of custom allocators is rather rare in my experience,
but those who need them will need to be diligent in their use. Calling
an alternate constructor/reset function doesn't seem like a heavy
burden for that small number of advanced users, particularly when it
is combined with RAII techniques for proper destruction.

Compare also the discussion of memory pools in the FAQs:

http://www.parashift.com/c++-faq-lit...html#faq-11.14

Cheers! --M
Aug 21 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
1535
by: Orjan Westin | last post by:
Hi, I have an interesting (read frustrating) problem. I'm writing a generic container class, which holds data as well as links to other instances of itself, like this: template<class T> class node { public:
2
3450
by: Joshua Kolden | last post by:
STL allocators are templates so that when you write one you are obliged to make it work with any type. However, the Intel IPP library that we use has memory aligned allocators for each of 15 different types. For example an 8 bit unsigned array is allocated with ippsMalloc_8u(size). So I want to create memory aligned allocators for use with the STL (in particular the vector container) that is fast (due to alignment), and pointer...
7
3082
by: Grahamo | last post by:
Hi, can anybody tell me where I can get the boiler plate code for std::allocator. I need to have my version of new and delete called and want to get reference code. My compilers headers are all over the place with #ifdefs and what not, I'd like a clean copy. thanks much
3
2151
by: Alex Vinokur | last post by:
Compiler GNU g++ version 3.4.4 (cygming special) Custom allocator for vector (see below) checks a return value of 'operator new'. If that value is NULL, the allocator "allocates" no memory. Nevertheless the allocator produces "Segmentation fault (core dumped)". Is it possible to correct that allocator in order to avoid such behavior ------ foo.cpp ------
0
1315
by: joe | last post by:
I have created a custom allocator for a multiset, and I am having a problem it seems because while the allocator has memory available to be used which is returned, the objects are never constructed on top of that memory. I expected my "construct" method to be called to handle this, but no one calls it. No more than MAX_OBJS object of class Obj will ever be allocated. #include<iostream> #include <set>
3
1906
by: joe | last post by:
I have written a custom std allocator which follows the example in Stroustrup's book. I'm seeing a behavior I don't understand. My allocate method within the allocator looks like the following: (FooAllocator<T>) pointer allocate(size_type cnt, typename std::allocator<void>::const_pointer hint = 0)
9
3893
by: OuaisBla | last post by:
Although STL container can't support object by reference as a template argument. To make thing worse, allocator can't support stack based allocation. So: std::deque<std::string const &> is impossible to declare. But, it is also more than impossible to find a workaroung using a custom STL allocator because of the ugly and not object oriented design that was used. Thanks to many STL contributor for this, specially to PJ Plauger where...
3
4657
by: Mike | last post by:
Hi, I have a simple "memPool' class that simply maintains a linked list of chunks from which allocation requests are made. The whole thing is deleted all at once upon destruction. So far, so good. Then I tried to make an allocator for this and use it with std::list with no success. I modeled my allocator code from gcc's new_allocator.h. I modified the allocate() and deallocate() functions and copy constructors, and added a...
16
2707
by: PeterAPIIT | last post by:
Hello all C++ expert programmer, i have wrote partial general allocator for my container. After reading standard C++ library and code guru article, i have several questions. 1. Why allocator write forward declaration then allocation for void* rather than directly wrote allocator first ?
0
9901
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9750
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
11024
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10672
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10744
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
7909
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5738
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
4150
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3182
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.